summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-09-11 09:54:20 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-09-14 13:29:47 +0200
commit0eabb63c06f4041077860875c9ea71216adf4faa (patch)
treedf7b74fc3588426e23291d2f4015d0f814479a75
parent00d7cd2d5300524aeb885d8d51b2123aa0b44f6e (diff)
downloadscala-0eabb63c06f4041077860875c9ea71216adf4faa.tar.gz
scala-0eabb63c06f4041077860875c9ea71216adf4faa.tar.bz2
scala-0eabb63c06f4041077860875c9ea71216adf4faa.zip
SI-6323 prohibits reflection against free types
One of the use cases for free types is reification of local classes. The result is very seamless. Despite that local classes are not pickled, free types recreated the symbols referenced by local classes, so that we get our own symbol table, which can be analyzed with usual precision of pickled symbols and types. However when we try to use those symbols for reflection, we hit a problem. Scala runtime reflection uses its own mechanism for dealing with non-pickled types, which is incompatible with mini symbol tables used in free types. Therefore to prevent confusion, I prohibit using those symbols for reflection.
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala23
-rw-r--r--test/files/run/t6323.check1
-rw-r--r--test/files/run/t6323.scala21
3 files changed, 42 insertions, 3 deletions
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 9f2c3fc79c..455cc14789 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -133,6 +133,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
""".trim.stripMargin)
private def ErrorSetImmutableField(wannabe: Symbol) = throw new ScalaReflectionException(s"cannot set an immutable field ${wannabe.name}")
private def ErrorNotConstructor(wannabe: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a constructor of $owner, you provided $wannabe")
+ private def ErrorFree(member: Symbol, freeType: Symbol) = throw new ScalaReflectionException(s"cannot reflect ${member.kindString} ${member.name}, because it's a member of a free type ${freeType.name}")
def reflect[T: ClassTag](obj: T): InstanceMirror = new JavaInstanceMirror(obj)
@@ -154,13 +155,30 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
def moduleSymbol(rtcls: RuntimeClass): ModuleSymbol = classToScala(rtcls).companionModule.asModule
+ private def ensuringNotFree(wannabe: Symbol)(body: => Any) {
+ val freeType = wannabe.ownerChain find (_.isFreeType)
+ freeType match {
+ case Some(freeType) => ErrorFree(wannabe, freeType)
+ case _ => body
+ }
+ }
+
private def checkMemberOf(wannabe: Symbol, owner: ClassSymbol) {
if (wannabe.owner == AnyClass || wannabe.owner == AnyRefClass || wannabe.owner == ObjectClass) {
// do nothing
} else if (wannabe.owner == AnyValClass) {
if (!owner.isPrimitiveValueClass && !owner.isDerivedValueClass) ErrorNotMember(wannabe, owner)
} else {
- if (!(owner.info.baseClasses contains wannabe.owner)) ErrorNotMember(wannabe, owner)
+ ensuringNotFree(wannabe) {
+ if (!(owner.info.baseClasses contains wannabe.owner)) ErrorNotMember(wannabe, owner)
+ }
+ }
+ }
+
+ private def checkConstructorOf(wannabe: Symbol, owner: ClassSymbol) {
+ if (!wannabe.isClassConstructor) ErrorNotConstructor(wannabe, owner)
+ ensuringNotFree(wannabe) {
+ if (!owner.info.decls.toList.contains(wannabe)) ErrorNotConstructor(wannabe, owner)
}
}
@@ -386,8 +404,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
def erasure = symbol
def isStatic = false
def reflectConstructor(constructor: MethodSymbol) = {
- if (!constructor.isClassConstructor) ErrorNotConstructor(constructor, symbol)
- if (!symbol.info.decls.toList.contains(constructor)) ErrorNotConstructor(constructor, symbol)
+ checkConstructorOf(constructor, symbol)
new JavaConstructorMirror(outer, constructor)
}
def companion: Option[ModuleMirror] = symbol.companionModule match {
diff --git a/test/files/run/t6323.check b/test/files/run/t6323.check
new file mode 100644
index 0000000000..2219278a16
--- /dev/null
+++ b/test/files/run/t6323.check
@@ -0,0 +1 @@
+cannot reflect value a, because it's a member of a free type Test
diff --git a/test/files/run/t6323.scala b/test/files/run/t6323.scala
new file mode 100644
index 0000000000..625cfaae20
--- /dev/null
+++ b/test/files/run/t6323.scala
@@ -0,0 +1,21 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror => m}
+import scala.reflect.runtime.{universe => u}
+
+object Test extends App {
+ locally {
+ try {
+ case class Test(a:String,b:List[Int])
+
+ val lookAtMe = m.reflect(Test("a",List(5)))
+ val value = u.typeOf[Test]
+ val members = value.members
+ val member = value.members.filter(_.name.encoded == "a")
+ val aAccessor = lookAtMe.reflectMethod(member.head.asMethod)
+ val thisShouldBeA = aAccessor.apply()
+ println(thisShouldBeA)
+ } catch {
+ case ScalaReflectionException(msg) => println(msg)
+ }
+ }
+} \ No newline at end of file