summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.scala42
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectionUtils.scala2
-rw-r--r--test/files/run/t6411.check80
-rw-r--r--test/files/run/t6411.scala73
-rw-r--r--test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala1
12 files changed, 230 insertions, 26 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 7cc5176507..4a95791284 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
@@ -312,13 +312,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 = {
+ def existsParam(pred: Type => Boolean) = symbol.paramss.flatten.map(_.info).exists(pred)
if (isBytecodelessMethod(symbol)) new JavaBytecodelessMethodMirror(receiver, symbol)
- else if (symbol.paramss.flatten exists (p => isByNameParamType(p.info))) new JavaByNameMethodMirror(receiver, symbol)
+ else if (existsParam(isByNameParam) || existsParam(isValueClassParam)) new JavaTransformingMethodMirror(receiver, symbol)
else {
symbol.paramss.flatten.length match {
case 0 => new JavaVanillaMethodMirror0(receiver, symbol)
@@ -379,12 +383,38 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
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 JavaByNameMethodMirror(val receiver: Any, symbol: MethodSymbol)
+ // 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
+ val isByName = params.map(p => isByNameParam(p.info))
+ val isValueClass = params.map(p => isValueClassParam(p.info))
+ private def valueClassUnboxer(p: Symbol) = {
+ val fields @ (field :: _) = p.info.declarations.collect{ case ts: TermSymbol if ts.isParamAccessor && ts.isMethod => ts }.toList
+ assert(fields.length == 1, s"$p: $fields")
+ runtimeClass(p.info).getDeclaredMethod(field.name.toString)
+ }
+ val paramUnboxers = params.map(p => if (isValueClassParam(p.info)) valueClassUnboxer(p) else null)
+ val paramCount = params.length
+ }
+
+ private class JavaTransformingMethodMirror(val receiver: Any, symbol: MethodSymbol, metadata: MethodMetadata)
extends JavaMethodMirror(symbol) {
- def bind(newReceiver: Any) = new JavaByNameMethodMirror(newReceiver, symbol)
+ def this(receiver: Any, symbol: MethodSymbol) = this(receiver, symbol, new MethodMetadata(symbol))
+ override def bind(newReceiver: Any) = new JavaTransformingMethodMirror(newReceiver, symbol, metadata)
+
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)
+ import metadata._
+ 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 (isValueClass(i)) args1(i) = paramUnboxers(i).invoke(arg)
+ i += 1
+ }
+ jinvoke(jmeth, receiver, args1)
}
}
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
diff --git a/test/files/run/t6411.check b/test/files/run/t6411.check
new file mode 100644
index 0000000000..03055b5a8a
--- /dev/null
+++ b/test/files/run/t6411.check
@@ -0,0 +1,80 @@
+meth = method yg_1
+as seen by Scala reflection: def yg_1[T](y: Y[T]): T
+as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object)
+result = 1
+meth = method yg_1
+as seen by Scala reflection: def yg_1[T](y: Y[T]): T
+as seen by Java reflection: public java.lang.Object a$.yg_1(java.lang.Object)
+result = 1
+meth = method yi_2
+as seen by Scala reflection: def yi_2(y: Y[Int]): Int
+as seen by Java reflection: public int a$.yi_2(java.lang.Integer)
+result = 2
+meth = method yi_2
+as seen by Scala reflection: def yi_2(y: Y[Int]): Int
+as seen by Java reflection: public int a$.yi_2(java.lang.Integer)
+result = class java.lang.IllegalArgumentException: argument type mismatch
+meth = method ys_3
+as seen by Scala reflection: def ys_3(y: Y[String]): String
+as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String)
+result = class java.lang.IllegalArgumentException: argument type mismatch
+meth = method ys_3
+as seen by Scala reflection: def ys_3(y: Y[String]): String
+as seen by Java reflection: public java.lang.String a$.ys_3(java.lang.String)
+result = 3
+meth = method ya_4
+as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[])
+result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+meth = method ya_4
+as seen by Scala reflection: def ya_4(ys: Array[Y[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.ya_4(Y[])
+result = List(4)
+meth = method yl_5
+as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List)
+result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+meth = method yl_5
+as seen by Scala reflection: def yl_5(ys: List[Y[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.yl_5(scala.collection.immutable.List)
+result = List(5)
+meth = method zg_1
+as seen by Scala reflection: def zg_1[T](z: Z[T]): T
+as seen by Java reflection: public java.lang.Object a$.zg_1(Z)
+result = 1
+meth = method zg_1
+as seen by Scala reflection: def zg_1[T](z: Z[T]): T
+as seen by Java reflection: public java.lang.Object a$.zg_1(Z)
+result = 1
+meth = method zi_2
+as seen by Scala reflection: def zi_2(z: Z[Int]): Int
+as seen by Java reflection: public int a$.zi_2(Z)
+result = 2
+meth = method zi_2
+as seen by Scala reflection: def zi_2(z: Z[Int]): Int
+as seen by Java reflection: public int a$.zi_2(Z)
+result = class java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
+meth = method zs_3
+as seen by Scala reflection: def zs_3(z: Z[String]): String
+as seen by Java reflection: public java.lang.String a$.zs_3(Z)
+result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+meth = method zs_3
+as seen by Scala reflection: def zs_3(z: Z[String]): String
+as seen by Java reflection: public java.lang.String a$.zs_3(Z)
+result = 3
+meth = method za_4
+as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[])
+result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+meth = method za_4
+as seen by Scala reflection: def za_4(zs: Array[Z[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.za_4(Z[])
+result = List(4)
+meth = method zl_5
+as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List)
+result = class java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+meth = method zl_5
+as seen by Scala reflection: def zl_5(zs: List[Z[String]]): List[String]
+as seen by Java reflection: public scala.collection.immutable.List a$.zl_5(scala.collection.immutable.List)
+result = List(5)
diff --git a/test/files/run/t6411.scala b/test/files/run/t6411.scala
new file mode 100644
index 0000000000..d80f7f6a1e
--- /dev/null
+++ b/test/files/run/t6411.scala
@@ -0,0 +1,73 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.language.reflectiveCalls
+
+class Y[T](val i: T) extends AnyVal {
+ override def toString = s"Y($i)"
+}
+class Z[T](val i: T) extends AnyRef {
+ override def toString = s"Z($i)"
+}
+
+object a {
+ def yg_1[T](y: Y[T]) = y.i
+ def yi_2(y: Y[Int]) = y.i
+ def ys_3(y: Y[String]) = y.i
+ def ya_4(ys: Array[Y[String]]) = ys.toList.map(_.i)
+ def yl_5(ys: List[Y[String]]) = ys.map(_.i)
+ def yv_6(ys: Y[String]*) = ys.toList.map(_.i)
+
+ def zg_1[T](z: Z[T]) = z.i
+ def zi_2(z: Z[Int]) = z.i
+ def zs_3(z: Z[String]) = z.i
+ def za_4(zs: Array[Z[String]]) = zs.toList.map(_.i)
+ def zl_5(zs: List[Z[String]]) = zs.map(_.i)
+ def zv_6(zs: Z[String]*) = zs.toList.map(_.i)
+}
+
+object Test extends App {
+ def test(methName: String, arg: Any) = {
+ val moduleA = cm.reflect(a)
+ val msym = moduleA.symbol.typeSignature.declaration(TermName(methName)).asMethod
+ println(s"meth = $msym")
+ val mmirror = moduleA.reflectMethod(msym)
+ val mresult =
+ try { mmirror(arg) }
+ catch {
+ case ex: Exception =>
+ val ex1 = scala.reflect.runtime.ReflectionUtils.unwrapThrowable(ex)
+ s"${ex1.getClass}: ${ex1.getMessage}"
+ }
+ println(s"as seen by Scala reflection: ${msym.asInstanceOf[scala.reflect.internal.Symbols#Symbol].defString}")
+ println(s"as seen by Java reflection: ${mmirror.asInstanceOf[{val jmeth: java.lang.reflect.Method}].jmeth}")
+ println(s"result = $mresult")
+ }
+
+ test("yg_1", new Y(1))
+ test("yg_1", new Y("1"))
+ test("yi_2", new Y(2))
+ test("yi_2", new Y("2"))
+ test("ys_3", new Y(3))
+ test("ys_3", new Y("3"))
+ test("ya_4", Array(new Y(4)))
+ test("ya_4", Array(new Y("4")))
+ test("yl_5", List(new Y(5)))
+ test("yl_5", List(new Y("5")))
+ // FIXME: disabled because of SI-7056
+ // test("yv_6", new Y(6))
+ // test("yv_6", new Y("6"))
+
+ test("zg_1", new Z(1))
+ test("zg_1", new Z("1"))
+ test("zi_2", new Z(2))
+ test("zi_2", new Z("2"))
+ test("zs_3", new Z(3))
+ test("zs_3", new Z("3"))
+ test("za_4", Array(new Z(4)))
+ test("za_4", Array(new Z("4")))
+ test("zl_5", List(new Z(5)))
+ test("zl_5", List(new Z("5")))
+ // FIXME: disabled because of SI-7056
+ // test("zv_6", new Z(6))
+ // test("zv_6", new Z("6"))
+} \ No newline at end of file
diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
index a3699a4eeb..b42e9a07cb 100644
--- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
+++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala
@@ -69,6 +69,7 @@ class SymbolTableForUnitTesting extends SymbolTable {
// Members declared in scala.reflect.internal.Required
def picklerPhase: scala.reflect.internal.Phase = SomePhase
+ def erasurePhase: scala.reflect.internal.Phase = SomePhase
// Members declared in scala.reflect.internal.SymbolTable
def currentRunId: Int = 1