diff options
22 files changed, 249 insertions, 70 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 5ca4712cd2..144cc841b4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -717,7 +717,8 @@ trait ContextErrors { Some(EOL + stackTraceString(realex)) } } catch { - // if the magic above goes boom, just fall back to uninformative, but better than nothing, getMessage + // the code above tries various tricks to detect the relevant portion of the stack trace + // if these tricks fail, just fall back to uninformative, but better than nothing, getMessage case NonFatal(ex) => macroLogVerbose("got an exception when processing a macro generated exception\n" + "offender = " + stackTraceString(realex) + "\n" + diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index e3f0756b6c..dd7f26861f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1334,7 +1334,7 @@ trait Implicits { def wrapResult(tree: Tree): SearchResult = if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter) - /** Materializes implicits of magic types (currently, manifests and tags). + /** Materializes implicits of predefined types (currently, manifests and tags). * Will be replaced by implicit macros once we fix them. */ private def materializeImplicit(pt: Type): SearchResult = diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 453f29d9e6..1201b1accd 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -96,7 +96,8 @@ case class StringContext(parts: String*) { * string literally. This is achieved by replacing each such occurrence by the * format specifier `%%`. */ - // The implementation is magically hardwired into `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f` + // The implementation is hardwired to `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f` + // Using the mechanism implemented in `scala.tools.reflect.FastTrack` def f(args: Any*): String = ??? // macro } diff --git a/src/library/scala/reflect/base/Universe.scala b/src/library/scala/reflect/base/Universe.scala index 11290401ec..36b85ca714 100644 --- a/src/library/scala/reflect/base/Universe.scala +++ b/src/library/scala/reflect/base/Universe.scala @@ -61,6 +61,7 @@ abstract class Universe extends Symbols * * Since reified trees can be compiled outside of the scope they've been created in, * special measures are taken to ensure that all members accessed in the reifee remain visible */ - // implementation is magically hardwired to `scala.reflect.reify.Taggers` + // implementation is hardwired to `scala.reflect.reify.Taggers` + // using the mechanism implemented in `scala.tools.reflect.FastTrack` def reify[T](expr: T): Expr[T] = ??? // macro }
\ No newline at end of file diff --git a/src/library/scala/reflect/macros/internal/package.scala b/src/library/scala/reflect/macros/internal/package.scala index aca2b765f1..8457285752 100644 --- a/src/library/scala/reflect/macros/internal/package.scala +++ b/src/library/scala/reflect/macros/internal/package.scala @@ -4,7 +4,8 @@ import scala.reflect.base.{Universe => BaseUniverse} import scala.reflect.ClassTag // anchors for materialization macros emitted during tag materialization in Implicits.scala -// implementation is magically hardwired into `scala.reflect.reify.Taggers` +// implementation is hardwired into `scala.reflect.reify.Taggers` +// using the mechanism implemented in `scala.tools.reflect.FastTrack` // todo. once we have implicit macros for tag generation, we can remove these anchors package object internal { private[scala] def materializeClassTag[T](u: BaseUniverse): ClassTag[T] = ??? // macro diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index baf200bd30..c7f1d2fcac 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -16,6 +16,7 @@ import scala.collection.generic.{ Sorted } import scala.reflect.{ ClassTag, classTag } import scala.util.control.ControlThrowable import scala.xml.{ Node, MetaData } +import java.lang.{ Class => jClass } import java.lang.Double.doubleToLongBits import java.lang.reflect.{ Modifier, Method => JMethod } @@ -29,10 +30,10 @@ object ScalaRunTime { def isArray(x: Any, atLevel: Int): Boolean = x != null && isArrayClass(x.getClass, atLevel) - private def isArrayClass(clazz: Class[_], atLevel: Int): Boolean = + private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean = clazz.isArray && (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1)) - def isValueClass(clazz: Class[_]) = clazz.isPrimitive() + def isValueClass(clazz: jClass[_]) = clazz.isPrimitive() def isTuple(x: Any) = x != null && tupleNames(x.getClass.getName) def isAnyVal(x: Any) = x match { case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true @@ -51,7 +52,7 @@ object ScalaRunTime { /** Return the class object representing an array with element class `clazz`. */ - def arrayClass(clazz: Class[_]): Class[_] = { + def arrayClass(clazz: jClass[_]): jClass[_] = { // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] else java.lang.reflect.Array.newInstance(clazz, 0).getClass @@ -59,18 +60,19 @@ object ScalaRunTime { /** Return the class object representing elements in arrays described by a given schematic. */ - def arrayElementClass(schematic: Any): Class[_] = schematic match { - case cls: Class[_] => cls.getComponentType + def arrayElementClass(schematic: Any): jClass[_] = schematic match { + case cls: jClass[_] => cls.getComponentType case tag: ClassTag[_] => tag.runtimeClass - case _ => throw new UnsupportedOperationException("unsupported schematic %s (%s)".format(schematic, if (schematic == null) "null" else schematic.getClass)) + case _ => + throw new UnsupportedOperationException(s"unsupported schematic $schematic (${schematic.getClass})") } /** Return the class object representing an unboxed value type, * e.g. classOf[int], not classOf[java.lang.Integer]. The compiler * rewrites expressions like 5.getClass to come here. */ - def anyValClass[T <: AnyVal : ClassTag](value: T): Class[T] = - classTag[T].runtimeClass.asInstanceOf[Class[T]] + def anyValClass[T <: AnyVal : ClassTag](value: T): jClass[T] = + classTag[T].runtimeClass.asInstanceOf[jClass[T]] /** Retrieve generic array element */ def array_apply(xs: AnyRef, idx: Int): Any = xs match { diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index 376e0e9bdb..4961424e1b 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -217,6 +217,7 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP "-Dpartest.output="+outDir.getAbsolutePath, "-Dpartest.lib="+LATEST_LIB, "-Dpartest.reflect="+LATEST_REFLECT, + "-Dpartest.comp="+LATEST_COMP, "-Dpartest.cwd="+outDir.getParent, "-Dpartest.test-path="+testFullPath, "-Dpartest.testname="+fileBase, diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 8853b872c0..3bd7f4f4fa 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -65,6 +65,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => */ abstract class ClassfileAnnotArg extends Product implicit val JavaArgumentTag = ClassTag[ClassfileAnnotArg](classOf[ClassfileAnnotArg]) + case object UnmappableAnnotArg extends ClassfileAnnotArg /** Represents a compile-time Constant (`Boolean`, `Byte`, `Short`, * `Char`, `Int`, `Long`, `Float`, `Double`, `String`, `java.lang.Class` or @@ -173,11 +174,14 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => this } - override def toString = ( - atp + - (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") + - (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "") - ) + override def toString = completeAnnotationToString(this) + } + + private[scala] def completeAnnotationToString(annInfo: AnnotationInfo) = { + import annInfo._ + val s_args = if (!args.isEmpty) args.mkString("(", ", ", ")") else "" + val s_assocs = if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "" + s"${atp}${s_args}${s_assocs}" } /** Symbol annotations parsed in `Namer` (typeCompleter of @@ -215,7 +219,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => * * `assocs` stores arguments to classfile annotations as name-value pairs. */ - sealed abstract class AnnotationInfo extends AnnotationApi { + abstract class AnnotationInfo extends AnnotationApi { def atp: Type def args: List[Tree] def assocs: List[(Name, ClassfileAnnotArg)] diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 6d7aa19738..4a5ace4248 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -1116,7 +1116,8 @@ trait Definitions extends api.StandardDefinitions { /** Is symbol a phantom class for which no runtime representation exists? */ lazy val isPhantomClass = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) - lazy val magicSymbols = List( + /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ + lazy val syntheticCoreClasses = List( AnnotationDefaultAttr, // #2264 RepeatedParamClass, JavaRepeatedParamClass, @@ -1127,7 +1128,10 @@ trait Definitions extends api.StandardDefinitions { NullClass, NothingClass, SingletonClass, - EqualsPatternClass, + EqualsPatternClass + ) + /** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ + lazy val syntheticCoreMethods = List( Any_==, Any_!=, Any_equals, @@ -1145,10 +1149,19 @@ trait Definitions extends api.StandardDefinitions { Object_synchronized, Object_isInstanceOf, Object_asInstanceOf, - String_+, + String_+ + ) + /** Lists core classes that do have underlying bytecode, but are adjusted on-the-fly in every reflection universe */ + lazy val hijackedCoreClasses = List( ComparableClass, JavaSerializableClass ) + /** Lists symbols that are synthesized or hijacked by the compiler. + * + * Such symbols either don't have any underlying bytecode at all ("synthesized") + * or get loaded from bytecode but have their metadata adjusted ("hijacked"). + */ + lazy val symbolsNotPresentInBytecode = syntheticCoreClasses ++ syntheticCoreMethods ++ hijackedCoreClasses /** Is the symbol that of a parent which is added during parsing? */ lazy val isPossibleSyntheticParent = ProductClass.toSet[Symbol] + ProductRootClass + SerializableClass @@ -1212,7 +1225,8 @@ trait Definitions extends api.StandardDefinitions { def init() { if (isInitialized) return - val forced = magicSymbols // force initialization of every symbol that is entered as a side effect + // force initialization of every symbol that is synthesized or hijacked by the compiler + val forced = symbolsNotPresentInBytecode isInitialized = true } //init diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala index be2661149a..47978821a3 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -9,6 +9,7 @@ import java.lang.reflect.{ Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField, Member => jMember, Type => jType, TypeVariable => jTypeVariable, Array => jArray, GenericDeclaration, GenericArrayType, ParameterizedType, WildcardType, AnnotatedElement } +import java.lang.annotation.{Annotation => jAnnotation} import java.io.IOException import internal.MissingRequirementError import internal.pickling.ByteCodecs @@ -23,7 +24,7 @@ import scala.language.existentials import scala.runtime.{ScalaRunTime, BoxesRunTime} import scala.reflect.internal.util.Collections._ -trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: SymbolTable => +trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { thisUniverse: SymbolTable => private lazy val mirrors = new WeakHashMap[ClassLoader, WeakReference[JavaMirror]]() @@ -62,9 +63,9 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym class JavaMirror(owner: Symbol, /** Class loader that is a mastermind behind the reflexive mirror */ val classLoader: ClassLoader - ) extends Roots(owner) with super.JavaMirror { wholemirror => + ) extends Roots(owner) with super.JavaMirror { thisMirror => - val universe: self.type = self + val universe: thisUniverse.type = thisUniverse import definitions._ @@ -135,6 +136,53 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a constructor of $owner, you provided $sym") private def ErrorFree(member: Symbol, freeType: Symbol) = throw new ScalaReflectionException(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}") + /** Helper functions for extracting typed values from a (Class[_], Any) + * representing an annotation argument. + */ + private object toAnnotArg { + val StringClass = classOf[String] + val ClassClass = classOf[jClass[_]] + object PrimitiveClass { def unapply(x: jClass[_]) = x.isPrimitive } + object EnumClass { def unapply(x: jClass[_]) = x.isEnum } + object ArrayClass { def unapply(x: jClass[_]) = x.isArray } + object AnnotationClass { def unapply(x: jClass[_]) = x.isAnnotation } + + object ConstantArg { + def enumToSymbol(enum: Enum[_]): Symbol = + classToScala(enum.getClass).typeSignature.declaration(enum.name: TermName) + + def unapply(schemaAndValue: (jClass[_], Any)): Option[Any] = schemaAndValue match { + case (StringClass | PrimitiveClass(), value) => Some(value) + case (ClassClass, value: jClass[_]) => Some(classToScala(value).toType) + case (EnumClass(), value: Enum[_]) => Some(enumToSymbol(value)) + case _ => None + } + } + def apply(schemaAndValue: (jClass[_], Any)): ClassfileAnnotArg = schemaAndValue match { + case ConstantArg(value) => LiteralAnnotArg(Constant(value)) + case (clazz @ ArrayClass(), value: Array[_]) => ArrayAnnotArg(value map (x => apply(ScalaRunTime.arrayElementClass(clazz) -> x))) + case (AnnotationClass(), value: jAnnotation) => NestedAnnotArg(JavaAnnotationProxy(value)) + case _ => UnmappableAnnotArg + } + } + private case class JavaAnnotationProxy(jann: jAnnotation) extends AnnotationInfo { + override val atp: Type = classToScala(jann.annotationType).toType + override val args: List[Tree] = Nil + override def original: Tree = EmptyTree + override def setOriginal(t: Tree): this.type = throw new Exception("setOriginal inapplicable for " + this) + override def pos: Position = NoPosition + override def setPos(pos: Position): this.type = throw new Exception("setPos inapplicable for " + this) + override def toString = completeAnnotationToString(this) + + // todo. find out the exact order of assocs as they are written in the class file + // currently I'm simply sorting the methods to guarantee stability of the output + override lazy val assocs: List[(Name, ClassfileAnnotArg)] = ( + jann.annotationType.getDeclaredMethods.sortBy(_.getName).toList map (m => + (m.getName: TermName) -> toAnnotArg(m.getReturnType -> m.invoke(jann)) + ) + ) + } + def reflect[T: ClassTag](obj: T): InstanceMirror = new JavaInstanceMirror(obj) def reflectClass(cls: ClassSymbol): ClassMirror = { @@ -190,7 +238,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym private class JavaInstanceMirror[T: ClassTag](val instance: T) extends InstanceMirror { - def symbol = wholemirror.classSymbol(preciseClass(instance)) + def symbol = thisMirror.classSymbol(preciseClass(instance)) def reflectField(field: TermSymbol): FieldMirror = { checkMemberOf(field, symbol) if ((field.isMethod && !field.isAccessor) || field.isModule) ErrorNotField(field) @@ -265,14 +313,13 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym // the "symbol == Any_getClass || symbol == Object_getClass" test doesn't cut it // because both AnyVal and its primitive descendants define their own getClass methods private def isGetClass(meth: MethodSymbol) = meth.name.toString == "getClass" && meth.params.flatten.isEmpty - private def isMagicPrimitiveMethod(meth: MethodSymbol) = meth.owner.isPrimitiveValueClass - private def isStringConcat(meth: MethodSymbol) = meth == String_+ || (isMagicPrimitiveMethod(meth) && meth.returnType =:= StringClass.toType) - lazy val magicMethodOwners = Set[Symbol](AnyClass, AnyValClass, AnyRefClass, ObjectClass, ArrayClass) ++ ScalaPrimitiveValueClasses - lazy val nonMagicObjectMethods = Set[Symbol](Object_clone, Object_equals, Object_finalize, Object_hashCode, Object_toString, - Object_notify, Object_notifyAll) ++ ObjectClass.info.member(nme.wait_).asTerm.alternatives.map(_.asMethod) - private def isMagicMethod(meth: MethodSymbol): Boolean = { - if (isGetClass(meth) || isStringConcat(meth) || isMagicPrimitiveMethod(meth) || meth == Predef_classOf || meth.isTermMacro) return true - magicMethodOwners(meth.owner) && !nonMagicObjectMethods(meth) + private def isStringConcat(meth: MethodSymbol) = meth == String_+ || (meth.owner.isPrimitiveValueClass && meth.returnType =:= StringClass.toType) + lazy val bytecodelessMethodOwners = Set[Symbol](AnyClass, AnyValClass, AnyRefClass, ObjectClass, ArrayClass) ++ ScalaPrimitiveValueClasses + lazy val bytecodefulObjectMethods = Set[Symbol](Object_clone, Object_equals, Object_finalize, Object_hashCode, Object_toString, + Object_notify, Object_notifyAll) ++ ObjectClass.info.member(nme.wait_).asTerm.alternatives.map(_.asMethod) + private def isBytecodelessMethod(meth: MethodSymbol): Boolean = { + if (isGetClass(meth) || isStringConcat(meth) || meth.owner.isPrimitiveValueClass || meth == Predef_classOf || meth.isTermMacro) return true + bytecodelessMethodOwners(meth.owner) && !bytecodefulObjectMethods(meth) } // unlike other mirrors, method mirrors are created by a factory @@ -280,7 +327,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym // therefore we move special cases into separate subclasses // rather than have them on a hot path them in a unified implementation of the `apply` method private def mkJavaMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): JavaMethodMirror = { - if (isMagicMethod(symbol)) new JavaMagicMethodMirror(receiver, symbol) + if (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol) else if (symbol.params.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol) else new JavaVanillaMethodMirror(receiver, symbol) } @@ -315,11 +362,11 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym } } - private class JavaMagicMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol) + private class JavaBytecodelessMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol) extends JavaMethodMirror(symbol) { def apply(args: Any*): Any = { // checking type conformance is too much of a hassle, so we don't do it here - // actually it's not even necessary, because we manually dispatch arguments to magic methods below + // actually it's not even necessary, because we manually dispatch arguments below val params = symbol.paramss.flatten val perfectMatch = args.length == params.length // todo. this doesn't account for multiple vararg parameter lists @@ -337,36 +384,36 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym def objArgs = args.asInstanceOf[Seq[AnyRef]] def fail(msg: String) = throw new ScalaReflectionException(msg + ", it cannot be invoked with mirrors") - def invokeMagicPrimitiveMethod = { + def invokePrimitiveMethod = { val jmeths = classOf[BoxesRunTime].getDeclaredMethods.filter(_.getName == nme.primitiveMethodName(symbol.name).toString) assert(jmeths.length == 1, jmeths.toList) jinvoke(jmeths.head, null, objReceiver +: objArgs) } symbol match { - case Any_== | Object_== => ScalaRunTime.inlinedEquals(objReceiver, objArg0) - case Any_!= | Object_!= => !ScalaRunTime.inlinedEquals(objReceiver, objArg0) - case Any_## | Object_## => ScalaRunTime.hash(objReceiver) - case Any_equals => receiver.equals(objArg0) - case Any_hashCode => receiver.hashCode - case Any_toString => receiver.toString - case Object_eq => objReceiver eq objArg0 - case Object_ne => objReceiver ne objArg0 - case Object_synchronized => objReceiver.synchronized(objArg0) - case sym if isGetClass(sym) => preciseClass(receiver) - case Any_asInstanceOf => fail("Any.asInstanceOf requires a type argument") - case Any_isInstanceOf => fail("Any.isInstanceOf requires a type argument") - case Object_asInstanceOf => fail("AnyRef.$asInstanceOf is an internal method") - case Object_isInstanceOf => fail("AnyRef.$isInstanceOf is an internal method") - case Array_length => ScalaRunTime.array_length(objReceiver) - case Array_apply => ScalaRunTime.array_apply(objReceiver, args(0).asInstanceOf[Int]) - case Array_update => ScalaRunTime.array_update(objReceiver, args(0).asInstanceOf[Int], args(1)) - case Array_clone => ScalaRunTime.array_clone(objReceiver) - case sym if isStringConcat(sym) => receiver.toString + objArg0 - case sym if isMagicPrimitiveMethod(sym) => invokeMagicPrimitiveMethod - case sym if sym == Predef_classOf => fail("Predef.classOf is a compile-time function") - case sym if sym.isTermMacro => fail(s"${symbol.fullName} is a macro, i.e. a compile-time function") - case _ => assert(false, this) + case Any_== | Object_== => ScalaRunTime.inlinedEquals(objReceiver, objArg0) + case Any_!= | Object_!= => !ScalaRunTime.inlinedEquals(objReceiver, objArg0) + case Any_## | Object_## => ScalaRunTime.hash(objReceiver) + case Any_equals => receiver.equals(objArg0) + case Any_hashCode => receiver.hashCode + case Any_toString => receiver.toString + case Object_eq => objReceiver eq objArg0 + case Object_ne => objReceiver ne objArg0 + case Object_synchronized => objReceiver.synchronized(objArg0) + case sym if isGetClass(sym) => preciseClass(receiver) + case Any_asInstanceOf => fail("Any.asInstanceOf requires a type argument") + case Any_isInstanceOf => fail("Any.isInstanceOf requires a type argument") + case Object_asInstanceOf => fail("AnyRef.$asInstanceOf is an internal method") + case Object_isInstanceOf => fail("AnyRef.$isInstanceOf is an internal method") + case Array_length => ScalaRunTime.array_length(objReceiver) + case Array_apply => ScalaRunTime.array_apply(objReceiver, args(0).asInstanceOf[Int]) + case Array_update => ScalaRunTime.array_update(objReceiver, args(0).asInstanceOf[Int], args(1)) + case Array_clone => ScalaRunTime.array_clone(objReceiver) + case sym if isStringConcat(sym) => receiver.toString + objArg0 + case sym if sym.owner.isPrimitiveValueClass => invokePrimitiveMethod + case sym if sym == Predef_classOf => fail("Predef.classOf is a compile-time function") + case sym if sym.isTermMacro => fail(s"${symbol.fullName} is a macro, i.e. a compile-time function") + case _ => assert(false, this) } } } @@ -469,7 +516,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym } private object unpickler extends UnPickler { - val global: self.type = self + val global: thisUniverse.type = thisUniverse } /** how connected???? @@ -573,7 +620,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym * Note: If `sym` is a method or constructor, its parameter annotations are copied as well. */ private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) { - // to do: implement + sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList } /** @@ -612,11 +659,12 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym } override def complete(sym: Symbol): Unit = { + if (jclazz.isEnum) throw new ScalaReflectionException("implementation restriction: Java enums are not supported") load(sym) completeRest() } - def completeRest(): Unit = self.synchronized { + def completeRest(): Unit = thisUniverse.synchronized { val tparams = clazz.rawInfo.typeParams val parents = try { @@ -1200,9 +1248,9 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym mirrors(rootToLoader getOrElseUpdate(root, findLoader)).get.get } - private lazy val magicClasses: Map[(String, Name), Symbol] = { + private lazy val syntheticCoreClasses: Map[(String, Name), Symbol] = { def mapEntry(sym: Symbol): ((String, Name), Symbol) = (sym.owner.fullName, sym.name) -> sym - Map() ++ (definitions.magicSymbols filter (_.isType) map mapEntry) + Map() ++ (definitions.syntheticCoreClasses map mapEntry) } /** 1. If `owner` is a package class (but not the empty package) and `name` is a term name, make a new package @@ -1221,9 +1269,12 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym if (name.isTermName && !owner.isEmptyPackageClass) return mirror.makeScalaPackage( if (owner.isRootSymbol) name.toString else owner.fullName+"."+name) - magicClasses get (owner.fullName, name) match { + syntheticCoreClasses get (owner.fullName, name) match { case Some(tsym) => - owner.info.decls enter tsym + // synthetic core classes are only present in root mirrors + // because Definitions.scala, which initializes and enters them, only affects rootMirror + // therefore we need to enter them manually for non-root mirrors + if (mirror ne thisUniverse.rootMirror) owner.info.decls enter tsym return tsym case None => } diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala index d325cf6a16..7b9f69e657 100644 --- a/src/reflect/scala/reflect/runtime/package.scala +++ b/src/reflect/scala/reflect/runtime/package.scala @@ -5,7 +5,8 @@ package object runtime { // type is api.JavaUniverse because we only want to expose the `scala.reflect.api.*` subset of reflection lazy val universe: api.JavaUniverse = new runtime.JavaUniverse - // implementation magically hardwired to the `currentMirror` method below + // implementation hardwired to the `currentMirror` method below + // using the mechanism implemented in `scala.tools.reflect.FastTrack` def currentMirror: universe.Mirror = ??? // macro } diff --git a/test/files/run/reflection-java-annotations.check b/test/files/run/reflection-java-annotations.check new file mode 100644 index 0000000000..84cfd03358 --- /dev/null +++ b/test/files/run/reflection-java-annotations.check @@ -0,0 +1,22 @@ +Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> import scala.reflect.runtime.universe._
+import scala.reflect.runtime.universe._
+
+scala> val sym = typeOf[Foo].typeSymbol
+sym: reflect.runtime.universe.Symbol = class Foo
+
+scala> sym.typeSignature
+res0: reflect.runtime.universe.Type = java.lang.Object{def <init>(): Foo}
+
+scala> sym.getAnnotations foreach (_.javaArgs)
+
+scala> println(sym.getAnnotations)
+List(ComplexAnnotation(v1 = 1, v10 = "hello", v101 = [101, 101], v102 = [102, 102], v103 = ['g', 'g'], v104 = [104, 104], v105 = [105L, 105L], v106 = [106.0, 106.0], v107 = [107.0, 107.0], v108 = [false, true], v11 = classOf[Foo], v110 = ["hello", "world"], v111 = [classOf[SimpleAnnotation], classOf[ComplexAnnotation]], v113 = [SimpleAnnotation(v1 = 21, v10 = "world2", v11 = classOf[ComplexAnnotation], v2 = 22, v3 = '\027', v4 = 24, v5 = 25L, v6 = 26.0, v7 = 27.0, v8 = false)], v13 = SimpleAnnotation(v1 = 11, v10 = "world1", v11 = classOf[SimpleAnnotation], v2 = 12, v3 = '\r', v4 = 14, v5 = 15L, v6 = 16.0, v7 = 17.0, v8 = false), v2 = 2, v3 = '\03', v4 = 4, v5 = 5L, v6 = 6.0, v7 = 7.0, v8 = false))
+
+scala>
+
+scala>
diff --git a/test/files/run/reflection-java-annotations.jar.desired.sha1 b/test/files/run/reflection-java-annotations.jar.desired.sha1 new file mode 100644 index 0000000000..430e7626e6 --- /dev/null +++ b/test/files/run/reflection-java-annotations.jar.desired.sha1 @@ -0,0 +1 @@ +c35876a529c6be33bdda7b3f48ac8ae800d2f36a ?reflection-java-annotations.jar diff --git a/test/files/run/reflection-java-annotations.scala b/test/files/run/reflection-java-annotations.scala new file mode 100644 index 0000000000..4a4fe2572d --- /dev/null +++ b/test/files/run/reflection-java-annotations.scala @@ -0,0 +1,20 @@ +import scala.tools.partest._ +import scala.tools.nsc.Settings + +object Test extends ReplTest { + def code = """ + import scala.reflect.runtime.universe._ + val sym = typeOf[Foo].typeSymbol + sym.typeSignature + sym.getAnnotations foreach (_.javaArgs) + println(sym.getAnnotations) + """ + + override def transformSettings(settings: Settings): Settings = { + val thisFile = testPath.jfile.getAbsolutePath + val javaCompiledAnnotationsJar = (thisFile stripSuffix "scala") + "jar" + val classpath = List(sys.props("partest.lib"), sys.props("partest.reflect"), sys.props("partest.comp"), javaCompiledAnnotationsJar) mkString sys.props("path.separator") + settings.processArguments(List("-cp", classpath), true) + settings + } +}
\ No newline at end of file diff --git a/test/files/run/t6329_repl.check b/test/files/run/t6329_repl.check new file mode 100644 index 0000000000..d4804fae37 --- /dev/null +++ b/test/files/run/t6329_repl.check @@ -0,0 +1,13 @@ +Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> classManifest[List[_]]
+warning: there were 1 deprecation warnings; re-run with -deprecation for details
+res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[Any]
+
+scala> scala.reflect.classTag[List[_]]
+res1: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
+
+scala>
diff --git a/test/files/run/t6329_repl.scala b/test/files/run/t6329_repl.scala new file mode 100644 index 0000000000..add6d64962 --- /dev/null +++ b/test/files/run/t6329_repl.scala @@ -0,0 +1,8 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |classManifest[List[_]] + |scala.reflect.classTag[List[_]] + |""".stripMargin +} diff --git a/test/files/run/t6329_repl_bug.check b/test/files/run/t6329_repl_bug.check new file mode 100644 index 0000000000..d4804fae37 --- /dev/null +++ b/test/files/run/t6329_repl_bug.check @@ -0,0 +1,13 @@ +Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> classManifest[List[_]]
+warning: there were 1 deprecation warnings; re-run with -deprecation for details
+res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[Any]
+
+scala> scala.reflect.classTag[List[_]]
+res1: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
+
+scala>
diff --git a/test/files/run/t6329_repl_bug.pending b/test/files/run/t6329_repl_bug.pending new file mode 100644 index 0000000000..9997d1771e --- /dev/null +++ b/test/files/run/t6329_repl_bug.pending @@ -0,0 +1,10 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import scala.reflect.runtime.universe._ + |import scala.reflect.runtime._ + |classManifest[List[_]] + |scala.reflect.classTag[List[_]] + |""".stripMargin +} diff --git a/test/files/run/t6329_vanilla.check b/test/files/run/t6329_vanilla.check new file mode 100644 index 0000000000..7e7c3d11df --- /dev/null +++ b/test/files/run/t6329_vanilla.check @@ -0,0 +1,2 @@ +scala.collection.immutable.List[Any]
+scala.collection.immutable.List
diff --git a/test/files/run/t6329_vanilla.scala b/test/files/run/t6329_vanilla.scala new file mode 100644 index 0000000000..a31cd5c72e --- /dev/null +++ b/test/files/run/t6329_vanilla.scala @@ -0,0 +1,4 @@ +object Test extends App { + println(classManifest[List[_]]) + println(scala.reflect.classTag[List[_]]) +}
\ No newline at end of file diff --git a/test/files/run/t6329_vanilla_bug.check b/test/files/run/t6329_vanilla_bug.check new file mode 100644 index 0000000000..7e7c3d11df --- /dev/null +++ b/test/files/run/t6329_vanilla_bug.check @@ -0,0 +1,2 @@ +scala.collection.immutable.List[Any]
+scala.collection.immutable.List
diff --git a/test/files/run/t6329_vanilla_bug.pending b/test/files/run/t6329_vanilla_bug.pending new file mode 100644 index 0000000000..404f90bf6e --- /dev/null +++ b/test/files/run/t6329_vanilla_bug.pending @@ -0,0 +1,7 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime._ + +object Test extends App { + println(classManifest[List[_]]) + println(scala.reflect.classTag[List[_]]) +}
\ No newline at end of file |