summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-02-10 09:11:58 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-02-10 09:11:58 +0100
commit5b3f0e693b063c775b7c9bc4c831643f8df4beea (patch)
treefba81dfcb8198749962bc78624a68d31fc153d61 /src
parent677149b351ea06923002f145fb202cf1d3924454 (diff)
parent6c7ceb611f574a578a67c2cd653b211e555b7898 (diff)
downloadscala-5b3f0e693b063c775b7c9bc4c831643f8df4beea.tar.gz
scala-5b3f0e693b063c775b7c9bc4c831643f8df4beea.tar.bz2
scala-5b3f0e693b063c775b7c9bc4c831643f8df4beea.zip
Merge pull request #3409 from xeno-by/ticket/6411
SI-6411 SI-7328 value class fixes for runtime reflection
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/PostErasure.scala12
-rw-r--r--src/compiler/scala/tools/reflect/ReflectGlobal.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Required.scala3
-rw-r--r--src/reflect/scala/reflect/internal/transform/PostErasure.scala19
-rw-r--r--src/reflect/scala/reflect/internal/transform/Transforms.scala11
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala240
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectionUtils.scala2
9 files changed, 193 insertions, 107 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 5492e563dd..1617db7517 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -81,6 +81,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase
+ def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase
+
// platform specific elements
protected class GlobalPlatform extends {
@@ -527,7 +529,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
} with Erasure
// phaseName = "posterasure"
- object postErasure extends {
+ override object postErasure extends {
val global: Global.this.type = Global.this
val runsAfter = List("erasure")
val runsRightAfter = Some("erasure")
diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
index cc78e27282..32987fed8c 100644
--- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala
@@ -8,7 +8,7 @@ package transform
/** This phase maps ErasedValueTypes to the underlying unboxed representation and
* performs peephole optimizations.
*/
-trait PostErasure extends InfoTransform with TypingTransformers {
+trait PostErasure extends InfoTransform with TypingTransformers with scala.reflect.internal.transform.PostErasure {
val global: Global
import global._
@@ -19,16 +19,6 @@ trait PostErasure extends InfoTransform with TypingTransformers {
def newTransformer(unit: CompilationUnit): Transformer = new PostErasureTransformer(unit)
override def changesBaseClasses = false
- object elimErasedValueType extends TypeMap {
- def apply(tp: Type) = tp match {
- case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp)))
- case ErasedValueType(_, underlying) => underlying
- case _ => mapOver(tp)
- }
- }
-
- def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp)
-
class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
override def transform(tree: Tree) = {
def finish(res: Tree) = logResult(s"Posterasure reduction\n Old: $tree\n New")(res)
diff --git a/src/compiler/scala/tools/reflect/ReflectGlobal.scala b/src/compiler/scala/tools/reflect/ReflectGlobal.scala
index f8ded56ec6..6f369212ad 100644
--- a/src/compiler/scala/tools/reflect/ReflectGlobal.scala
+++ b/src/compiler/scala/tools/reflect/ReflectGlobal.scala
@@ -12,9 +12,10 @@ class ReflectGlobal(currentSettings: Settings, reporter: Reporter, override val
extends Global(currentSettings, reporter) with scala.tools.reflect.ReflectSetup with scala.reflect.runtime.SymbolTable {
override def transformedType(sym: Symbol) =
- erasure.transformInfo(sym,
- uncurry.transformInfo(sym,
- refChecks.transformInfo(sym, sym.info)))
+ postErasure.transformInfo(sym,
+ erasure.transformInfo(sym,
+ uncurry.transformInfo(sym,
+ refChecks.transformInfo(sym, sym.info))))
override def isCompilerUniverse = true
diff --git a/src/reflect/scala/reflect/internal/Required.scala b/src/reflect/scala/reflect/internal/Required.scala
index 14db252a16..009bc39d4c 100644
--- a/src/reflect/scala/reflect/internal/Required.scala
+++ b/src/reflect/scala/reflect/internal/Required.scala
@@ -6,6 +6,9 @@ import settings.MutableSettings
trait Required { self: SymbolTable =>
def picklerPhase: Phase
+
+ def erasurePhase: Phase
+
def settings: MutableSettings
@deprecated("Interactive is implemented with a custom Global; this flag is ignored", "2.11.0") def forInteractive = false
diff --git a/src/reflect/scala/reflect/internal/transform/PostErasure.scala b/src/reflect/scala/reflect/internal/transform/PostErasure.scala
new file mode 100644
index 0000000000..f0c7d0f050
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/transform/PostErasure.scala
@@ -0,0 +1,19 @@
+package scala.reflect
+package internal
+package transform
+
+trait PostErasure {
+ val global: SymbolTable
+ import global._
+ import definitions._
+
+ object elimErasedValueType extends TypeMap {
+ def apply(tp: Type) = tp match {
+ case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp)))
+ case ErasedValueType(_, underlying) => underlying
+ case _ => mapOver(tp)
+ }
+ }
+
+ def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp)
+}
diff --git a/src/reflect/scala/reflect/internal/transform/Transforms.scala b/src/reflect/scala/reflect/internal/transform/Transforms.scala
index fa185db22f..296ccde443 100644
--- a/src/reflect/scala/reflect/internal/transform/Transforms.scala
+++ b/src/reflect/scala/reflect/internal/transform/Transforms.scala
@@ -26,17 +26,20 @@ trait Transforms { self: SymbolTable =>
private val refChecksLazy = new Lazy(new { val global: Transforms.this.type = self } with RefChecks)
private val uncurryLazy = new Lazy(new { val global: Transforms.this.type = self } with UnCurry)
private val erasureLazy = new Lazy(new { val global: Transforms.this.type = self } with Erasure)
+ private val postErasureLazy = new Lazy(new { val global: Transforms.this.type = self } with PostErasure)
def refChecks = refChecksLazy.force
def uncurry = uncurryLazy.force
def erasure = erasureLazy.force
+ def postErasure = postErasureLazy.force
def transformedType(sym: Symbol) =
- erasure.transformInfo(sym,
- uncurry.transformInfo(sym,
- refChecks.transformInfo(sym, sym.info)))
+ postErasure.transformInfo(sym,
+ erasure.transformInfo(sym,
+ uncurry.transformInfo(sym,
+ refChecks.transformInfo(sym, sym.info))))
def transformedType(tpe: Type) =
- erasure.scalaErasure(uncurry.uncurry(tpe))
+ postErasure.elimErasedValueType(erasure.scalaErasure(uncurry.uncurry(tpe)))
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 68c67bb1f8..bc95b839b7 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -16,7 +16,7 @@ import java.io.IOException
import scala.reflect.internal.{ MissingRequirementError, JavaAccFlags, JMethodOrConstructor }
import internal.pickling.ByteCodecs
import internal.pickling.UnPickler
-import scala.collection.mutable.{ HashMap, ListBuffer }
+import scala.collection.mutable.{ HashMap, ListBuffer, ArrayBuffer }
import internal.Flags._
import ReflectionUtils._
import scala.language.existentials
@@ -118,15 +118,16 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def abort(msg: String) = throw new ScalaReflectionException(msg)
- private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror")
- private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
- private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
- private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
- private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}")
- private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym")
- private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym")
- private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}")
- private def ErrorNonExistentField(sym: Symbol) = abort(
+ private def ErrorInnerClass(sym: Symbol) = abort(s"$sym is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror")
+ private def ErrorInnerModule(sym: Symbol) = abort(s"$sym is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
+ private def ErrorStaticClass(sym: Symbol) = abort(s"$sym is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
+ private def ErrorStaticModule(sym: Symbol) = abort(s"$sym is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
+ private def ErrorNotMember(sym: Symbol, owner: Symbol) = abort(s"expected a member of $owner, you provided ${sym.kindString} ${sym.fullName}")
+ private def ErrorNotField(sym: Symbol) = abort(s"expected a field or an accessor method symbol, you provided $sym")
+ private def ErrorNotConstructor(sym: Symbol, owner: Symbol) = abort(s"expected a constructor of $owner, you provided $sym")
+ private def ErrorArrayConstructor(sym: Symbol, owner: Symbol) = abort(s"Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead")
+ private def ErrorFree(member: Symbol, freeType: Symbol) = abort(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a weak type ${freeType.name}")
+ private def ErrorNonExistentField(sym: Symbol) = abort(
sm"""Scala field ${sym.name} isn't represented as a Java field, neither it has a Java accessor method
|note that private parameters of class constructors don't get mapped onto fields and/or accessors,
|unless they are used outside of their declaring constructors.""")
@@ -221,6 +222,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def checkConstructorOf(sym: Symbol, owner: ClassSymbol) {
if (!sym.isClassConstructor) ErrorNotConstructor(sym, owner)
+ if (owner == ArrayClass) ErrorArrayConstructor(sym, owner)
ensuringNotFree(sym) {
if (!owner.info.decls.toList.contains(sym)) ErrorNotConstructor(sym, owner)
}
@@ -247,7 +249,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
def reflectMethod(method: MethodSymbol): MethodMirror = {
checkMemberOf(method, symbol)
- mkJavaMethodMirror(instance, method)
+ mkMethodMirror(instance, method)
}
def reflectClass(cls: ClassSymbol): ClassMirror = {
if (cls.isStatic) ErrorStaticClass(cls)
@@ -262,16 +264,35 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
override def toString = s"instance mirror for $instance"
}
- private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol)
+ // caches value class metadata, so that we minimize the work that needs to be done during Mirror.apply
+ private class DerivedValueClassMetadata(info: Type) {
+ val symbol = info.typeSymbol
+ val isDerivedValueClass = symbol.isDerivedValueClass
+ lazy val boxer = runtimeClass(symbol.toType).getDeclaredConstructors().head
+ lazy val unboxer = {
+ val fields @ (field :: _) = symbol.toType.declarations.collect{ case ts: TermSymbol if ts.isParamAccessor && ts.isMethod => ts }.toList
+ assert(fields.length == 1, s"$symbol: $fields")
+ runtimeClass(symbol.asClass).getDeclaredMethod(field.name.toString)
+ }
+ }
+
+ private class JavaFieldMirror(val receiver: Any, val symbol: TermSymbol, metadata: DerivedValueClassMetadata)
extends FieldMirror {
+ def this(receiver: Any, symbol: TermSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.info))
+ def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol, metadata)
+ import metadata._
+
lazy val jfield = ensureAccessible(fieldToJava(symbol))
- def get = jfield get receiver
+ def get = {
+ val value = jfield get receiver
+ if (isDerivedValueClass) boxer.newInstance(value) else value
+ }
def set(value: Any) = {
// it appears useful to be able to set values of vals, therefore I'm disabling this check
// if (!symbol.isMutable) ErrorSetImmutableField(symbol)
- jfield.set(receiver, value)
+ jfield.set(receiver, if (isDerivedValueClass) unboxer.invoke(value) else value)
}
- def bind(newReceiver: Any) = new JavaFieldMirror(newReceiver, symbol)
+
override def toString = s"field mirror for ${symbol.fullName} (bound to $receiver)"
}
@@ -312,13 +333,17 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
bytecodelessMethodOwners(meth.owner) && !bytecodefulObjectMethods(meth)
}
+ private def isByNameParam(p: Type) = isByNameParamType(p)
+ private def isValueClassParam(p: Type) = p.typeSymbol.isDerivedValueClass
+
// unlike other mirrors, method mirrors are created by a factory
// that's because we want to have decent performance
// 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 (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol)
- else if (symbol.paramss.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol)
+ private def mkMethodMirror[T: ClassTag](receiver: T, symbol: MethodSymbol): MethodMirror = {
+ def existsParam(pred: Type => Boolean) = symbol.paramss.flatten.map(_.info).exists(pred)
+ if (isBytecodelessMethod(symbol)) new BytecodelessMethodMirror(receiver, symbol)
+ else if (existsParam(isByNameParam) || existsParam(isValueClassParam)) new JavaTransformingMethodMirror(receiver, symbol)
else {
symbol.paramss.flatten.length match {
case 0 => new JavaVanillaMethodMirror0(receiver, symbol)
@@ -330,68 +355,123 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
}
}
- private abstract class JavaMethodMirror(val symbol: MethodSymbol) extends MethodMirror {
+
+ private abstract class JavaMethodMirror(val symbol: MethodSymbol, protected val ret: DerivedValueClassMetadata) extends MethodMirror {
lazy val jmeth = ensureAccessible(methodToJava(symbol))
- def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+ lazy val jconstr = ensureAccessible(constructorToJava(symbol))
- def jinvoke(jmeth: jMethod, receiver: Any, args: Seq[Any]): Any = {
- val result = jinvokeraw(jmeth, receiver, args)
- if (jmeth.getReturnType == java.lang.Void.TYPE) ()
+ def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*)
+ else if (receiver == null) jconstr.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
+ else jconstr.newInstance((receiver +: args).asInstanceOf[Seq[AnyRef]]: _*)
+ def jinvoke(args: Seq[Any]): Any = {
+ val result = jinvokeraw(args)
+ if (!symbol.isConstructor && jmeth.getReturnType == java.lang.Void.TYPE) ()
+ else if (!symbol.isConstructor && ret.isDerivedValueClass) ret.boxer.newInstance(result.asInstanceOf[AnyRef])
else result
}
- override def toString = s"method mirror for ${showMethodSig(symbol)} (bound to $receiver)"
- }
-
- private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
- def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol)
- def apply(args: Any*): Any = jinvoke(jmeth, receiver, args)
- }
-
- private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol)
- extends JavaVanillaMethodMirror(receiver, symbol) {
- override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol)
- override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver)
- }
-
- private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol)
- extends JavaVanillaMethodMirror(receiver, symbol) {
- override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol)
- override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef])
- }
-
- private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol)
- extends JavaVanillaMethodMirror(receiver, symbol) {
- override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol)
- override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
- }
-
- private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol)
- extends JavaVanillaMethodMirror(receiver, symbol) {
- override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol)
- override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ override def toString = {
+ val what = if (symbol.isConstructor) "constructor mirror" else "method mirror"
+ s"$what for ${showMethodSig(symbol)} (bound to $receiver)"
+ }
}
- private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol)
- extends JavaVanillaMethodMirror(receiver, symbol) {
- override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol)
- override def jinvokeraw(jmeth: jMethod, receiver: Any, args: Seq[Any]) = jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
- }
+ private class JavaVanillaMethodMirror(val receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaMethodMirror(symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ def bind(newReceiver: Any) = new JavaVanillaMethodMirror(newReceiver, symbol, ret)
+ def apply(args: Any*): Any = jinvoke(args)
+ }
+
+ private class JavaVanillaMethodMirror0(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror0(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver)
+ else if (receiver == null) jconstr.newInstance()
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror1(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror1(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror2(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror2(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror3(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror3(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef])
+ }
+
+ private class JavaVanillaMethodMirror4(receiver: Any, symbol: MethodSymbol, ret: DerivedValueClassMetadata)
+ extends JavaVanillaMethodMirror(receiver, symbol, ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new DerivedValueClassMetadata(symbol.returnType))
+ override def bind(newReceiver: Any) = new JavaVanillaMethodMirror4(newReceiver, symbol, ret)
+ override def jinvokeraw(args: Seq[Any]) =
+ if (!symbol.isConstructor) jmeth.invoke(receiver, args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
+ else if (receiver == null) jconstr.newInstance(args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
+ else jconstr.newInstance(receiver.asInstanceOf[AnyRef], args(0).asInstanceOf[AnyRef], args(1).asInstanceOf[AnyRef], args(2).asInstanceOf[AnyRef], args(3).asInstanceOf[AnyRef])
+ }
+
+ // caches MethodSymbol metadata, so that we minimize the work that needs to be done during Mirror.apply
+ // TODO: vararg is only supported in the last parameter list (SI-6182), so we don't need to worry about the rest for now
+ private class MethodMetadata(symbol: MethodSymbol) {
+ private val params = symbol.paramss.flatten.toArray
+ private val vcMetadata = params.map(p => new DerivedValueClassMetadata(p.info))
+ val isByName = params.map(p => isByNameParam(p.info))
+ def isDerivedValueClass(i: Int) = vcMetadata(i).isDerivedValueClass
+ def paramUnboxers(i: Int) = vcMetadata(i).unboxer
+ val paramCount = params.length
+ val ret = new DerivedValueClassMetadata(symbol.returnType)
+ }
+
+ private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata)
+ extends JavaMethodMirror(symbol, metadata.ret) {
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol))
+ override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata)
+ import metadata._
- private class JavaByNameMethodMirror(val receiver: Any, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
- def bind(newReceiver: Any) = new JavaByNameMethodMirror(newReceiver, symbol)
def apply(args: Any*): Any = {
- val transformed = map2(args.toList, symbol.paramss.flatten)((arg, param) => if (isByNameParamType(param.info)) () => arg else arg)
- jinvoke(jmeth, receiver, transformed)
+ val args1 = new Array[Any](args.length)
+ var i = 0
+ while (i < args1.length) {
+ val arg = args(i)
+ if (i >= paramCount) args1(i) = arg // don't transform varargs
+ else if (isByName(i)) args1(i) = () => arg // don't transform by-name value class params
+ else if (isDerivedValueClass(i)) args1(i) = paramUnboxers(i).invoke(arg)
+ i += 1
+ }
+ jinvoke(args1)
}
}
- private class JavaBytecodelessMethodMirror[T: ClassTag](val receiver: T, symbol: MethodSymbol)
- extends JavaMethodMirror(symbol) {
- def bind(newReceiver: Any) = new JavaBytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol)
- def apply(args: Any*): Any = {
+ private class BytecodelessMethodMirror[T: ClassTag](val receiver: T, val symbol: MethodSymbol)
+ extends MethodMirror {
+ def bind(newReceiver: Any) = new BytecodelessMethodMirror(newReceiver.asInstanceOf[T], symbol)
+ override def toString = s"bytecodeless method mirror for ${showMethodSig(symbol)} (bound to $receiver)"
+
+ 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 below
val params = symbol.paramss.flatten
@@ -414,7 +494,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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)
+ val jmeth = jmeths.head
+ val result = jmeth.invoke(null, (objReceiver +: objArgs).asInstanceOf[Seq[AnyRef]]: _*)
+ if (jmeth.getReturnType == java.lang.Void.TYPE) ()
+ else result
}
symbol match {
@@ -445,23 +528,6 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
}
}
- private class JavaConstructorMirror(val outer: AnyRef, val symbol: MethodSymbol)
- extends MethodMirror {
- def bind(newReceiver: Any) = new JavaConstructorMirror(newReceiver.asInstanceOf[AnyRef], symbol)
- override val receiver = outer
- lazy val jconstr = ensureAccessible(constructorToJava(symbol))
- def apply(args: Any*): Any = {
- if (symbol.owner == ArrayClass)
- abort("Cannot instantiate arrays with mirrors. Consider using `scala.reflect.ClassTag(<class of element>).newArray(<length>)` instead")
-
- val effectiveArgs =
- if (outer == null) args.asInstanceOf[Seq[AnyRef]]
- else outer +: args.asInstanceOf[Seq[AnyRef]]
- jconstr.newInstance(effectiveArgs: _*)
- }
- override def toString = s"constructor mirror for ${showMethodSig(symbol)} (bound to $outer)"
- }
-
private abstract class JavaTemplateMirror
extends TemplateMirror {
def outer: AnyRef
@@ -474,7 +540,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def isStatic = false
def reflectConstructor(constructor: MethodSymbol) = {
checkConstructorOf(constructor, symbol)
- new JavaConstructorMirror(outer, constructor)
+ mkMethodMirror(outer, constructor)
}
override def toString = s"class mirror for ${symbol.fullName} (bound to $outer)"
}
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index cfd66744ff..f6556a442d 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -12,6 +12,8 @@ class JavaUniverse extends internal.SymbolTable with JavaUniverseForce with Refl
override def inform(msg: String): Unit = log(msg)
def picklerPhase = internal.SomePhase
+ def erasurePhase = internal.SomePhase
+
lazy val settings = new Settings
private val isLogging = sys.props contains "scala.debug.reflect"
diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
index 813c0e1386..d642b25127 100644
--- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
+++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
@@ -12,7 +12,7 @@ import scala.reflect.internal.util.AbstractFileClassLoader
/** A few java-reflection oriented utility functions useful during reflection bootstrapping.
*/
-private[scala] object ReflectionUtils {
+object ReflectionUtils {
// Unwraps some chained exceptions which arise during reflective calls.
def unwrapThrowable(x: Throwable): Throwable = x match {
case _: InvocationTargetException | // thrown by reflectively invoked method or constructor