diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-09-16 08:27:10 -0700 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-09-16 08:27:10 -0700 |
commit | 4d8d2e52361586f32a1a52b9a78728aca0d5bf0c (patch) | |
tree | 3a227e84d0c795bd3cb81bdcc8a9d98fc675054e | |
parent | 24580ac84242679619d27f20258078dd012c120a (diff) | |
parent | 05be78101c694974ae964bb26b48c1a0b5a372c1 (diff) | |
download | scala-4d8d2e52361586f32a1a52b9a78728aca0d5bf0c.tar.gz scala-4d8d2e52361586f32a1a52b9a78728aca0d5bf0c.tar.bz2 scala-4d8d2e52361586f32a1a52b9a78728aca0d5bf0c.zip |
Merge pull request #1311 from scalamacros/topic/magic
deals with magic
8 files changed, 76 insertions, 55 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/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..e56441b672 100644 --- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala +++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala @@ -23,7 +23,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 +62,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._ @@ -190,7 +190,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 +265,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 +279,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 +314,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 +336,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 +468,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???? @@ -616,7 +615,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym completeRest() } - def completeRest(): Unit = self.synchronized { + def completeRest(): Unit = thisUniverse.synchronized { val tparams = clazz.rawInfo.typeParams val parents = try { @@ -1200,9 +1199,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 +1220,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 } |