summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/api
diff options
context:
space:
mode:
authorPhilipp Haller <hallerp@gmail.com>2014-07-09 14:43:12 +0200
committerPhilipp Haller <hallerp@gmail.com>2014-07-15 14:03:49 +0200
commit5762110d0dc2cb492e34d5595c473aa0f9ca786a (patch)
tree974c218830fcab44f386c11be28a82b0ec3acc71 /src/reflect/scala/reflect/api
parent87bba9418ca891c436f386207b3b9e70b4a64c71 (diff)
downloadscala-5762110d0dc2cb492e34d5595c473aa0f9ca786a.tar.gz
scala-5762110d0dc2cb492e34d5595c473aa0f9ca786a.tar.bz2
scala-5762110d0dc2cb492e34d5595c473aa0f9ca786a.zip
SI-5919 TypeTags and Exprs should be serializable
- Make TypeCreator and TreeCreator extend Serializable. - When replacing a SerializedTypeTag with a TypeTag or WeakTypeTag, do not use scala.reflect.runtime.universe.rootMirror, since it is unlikely to find user classes; instead, create a runtime mirror using the context ClassLoader of the current thread. Use the same logic for SerializedExpr. - Remove writeObject/readObject methods from SerializedTypeTag and SerializedExpr since they are unused. - Add @throws annotation on writeReplace and readResolve methods. - Handle SecurityException if the current thread cannot access the context ClassLoader. - To make type tags of primitive value classes serializable, make PredefTypeCreator a top-level class. Otherwise, it would retain a reference to the enclosing Universe, rendering the TypeCreator non-serializable. Binary compatibility: - Keep nested PredefTypeCreator class to avoid backward binary incompatible change. - Keep `var` modifiers on the class parameters of SerializedTypeTag for backward binary compatibility. - Adds filter rules to forward binary compatibility whitelist: - `TypeCreator`, `PredefTypeCreator`, and `TreeCreator` must now extend from `Serializable`. - Must have new class `scala.reflect.api.PredefTypeCreator` to avoid problematic outer reference.
Diffstat (limited to 'src/reflect/scala/reflect/api')
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala22
-rw-r--r--src/reflect/scala/reflect/api/TreeCreator.scala6
-rw-r--r--src/reflect/scala/reflect/api/TypeCreator.scala2
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala40
4 files changed, 42 insertions, 28 deletions
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index 5b6ff2325c..6d401b5a79 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -9,6 +9,7 @@ package api
import scala.reflect.runtime.{universe => ru}
import scala.annotation.compileTimeOnly
+import java.io.ObjectStreamException
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
@@ -157,23 +158,22 @@ trait Exprs { self: Universe =>
|if you want to get a value of the underlying expression, add scala-compiler.jar to the classpath,
|import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedExpr(treec, implicitly[WeakTypeTag[T]].in(ru.rootMirror))
}
}
private[scala] class SerializedExpr(var treec: TreeCreator, var tag: ru.WeakTypeTag[_]) extends Serializable {
- private def writeObject(out: java.io.ObjectOutputStream): Unit = {
- out.writeObject(treec)
- out.writeObject(tag)
- }
-
- private def readObject(in: java.io.ObjectInputStream): Unit = {
- treec = in.readObject().asInstanceOf[TreeCreator]
- tag = in.readObject().asInstanceOf[ru.WeakTypeTag[_]]
- }
+ import scala.reflect.runtime.universe.{Expr, runtimeMirror}
+ @throws(classOf[ObjectStreamException])
private def readResolve(): AnyRef = {
- import ru._
- Expr(rootMirror, treec)(tag)
+ val loader: ClassLoader = try {
+ Thread.currentThread().getContextClassLoader()
+ } catch {
+ case se: SecurityException => null
+ }
+ val m = runtimeMirror(loader)
+ Expr(m, treec)(tag.in(m))
}
}
diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala
index 027c840955..000eaa1aa6 100644
--- a/src/reflect/scala/reflect/api/TreeCreator.scala
+++ b/src/reflect/scala/reflect/api/TreeCreator.scala
@@ -2,12 +2,12 @@ package scala
package reflect
package api
-/** This is an internal implementation class.
+/** A mirror-aware factory for trees.
*
* This class is used internally by Scala Reflection, and is not recommended for use in client code.
*
- * @group ReflectionAPI
+ * @group ReflectionAPI
*/
-abstract class TreeCreator {
+abstract class TreeCreator extends Serializable {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree
}
diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala
index 37fff90b43..cbd55b9428 100644
--- a/src/reflect/scala/reflect/api/TypeCreator.scala
+++ b/src/reflect/scala/reflect/api/TypeCreator.scala
@@ -8,6 +8,6 @@ package api
*
* @group ReflectionAPI
*/
-abstract class TypeCreator {
+abstract class TypeCreator extends Serializable {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type
}
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
index 1dfc84be69..1d53453bde 100644
--- a/src/reflect/scala/reflect/api/TypeTags.scala
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -9,6 +9,7 @@ package api
import java.lang.{ Class => jClass }
import scala.language.implicitConversions
+import java.io.ObjectStreamException
/**
* A `TypeTag[T]` encapsulates the runtime type representation of some type `T`.
@@ -233,6 +234,7 @@ trait TypeTags { self: Universe =>
val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]]
otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec)
}
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false)
}
@@ -293,10 +295,13 @@ trait TypeTags { self: Universe =>
val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]]
otherMirror.universe.TypeTag[T](otherMirror1, tpec)
}
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
}
/* @group TypeTags */
+ // This class only exists to silence MIMA complaining about a binary incompatibility.
+ // Only the top-level class (api.PredefTypeCreator) should be used.
private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = {
copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
@@ -304,8 +309,9 @@ trait TypeTags { self: Universe =>
}
/* @group TypeTags */
- private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new PredefTypeCreator(copyIn)) {
+ private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new api.PredefTypeCreator(copyIn)) {
override lazy val tpe: Type = _tpe
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
}
@@ -341,20 +347,28 @@ trait TypeTags { self: Universe =>
def symbolOf[T: WeakTypeTag]: TypeSymbol
}
+// This class should be final, but we can't do that in Scala 2.11.x without breaking
+// binary incompatibility.
+// Since instances of this class are serialized, this class should have a
+// SerialVersionUID annotation.
private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
- private def writeObject(out: java.io.ObjectOutputStream): Unit = {
- out.writeObject(tpec)
- out.writeBoolean(concrete)
- }
-
- private def readObject(in: java.io.ObjectInputStream): Unit = {
- tpec = in.readObject().asInstanceOf[TypeCreator]
- concrete = in.readBoolean()
+ import scala.reflect.runtime.universe.{TypeTag, WeakTypeTag, runtimeMirror}
+ @throws(classOf[ObjectStreamException])
+ private def readResolve(): AnyRef = {
+ val loader: ClassLoader = try {
+ Thread.currentThread().getContextClassLoader()
+ } catch {
+ case se: SecurityException => null
+ }
+ val m = runtimeMirror(loader)
+ if (concrete) TypeTag(m, tpec)
+ else WeakTypeTag(m, tpec)
}
+}
- private def readResolve(): AnyRef = {
- import scala.reflect.runtime.universe._
- if (concrete) TypeTag(rootMirror, tpec)
- else WeakTypeTag(rootMirror, tpec)
+/* @group TypeTags */
+private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator {
+ def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = {
+ copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
}
}