summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-01-31 15:02:48 +0100
committerEugene Burmako <xeno.by@gmail.com>2012-02-01 23:43:32 +0100
commit610027b3c50c6a46b26bcfe71013cebc172c146b (patch)
tree6522f581316a4a6b94f004cf2bfbdf34cc481fb2
parentfbd5efe49cf23b446762dfa5026e8bac82ab04fc (diff)
downloadscala-610027b3c50c6a46b26bcfe71013cebc172c146b.tar.gz
scala-610027b3c50c6a46b26bcfe71013cebc172c146b.tar.bz2
scala-610027b3c50c6a46b26bcfe71013cebc172c146b.zip
Hardens reification against rare kinds of Constants
Importers now correctly process constants that carry types and symbols. However, it is still impossible to reify classOf for a class/trait that is defined inside a quasiquote. Theoretically, this can be implemented, but will require attaching original trees to classOf constants, which needs much more effort.
-rw-r--r--src/compiler/scala/reflect/internal/Constants.scala2
-rw-r--r--src/compiler/scala/reflect/internal/Importers.scala17
-rw-r--r--src/compiler/scala/tools/nsc/transform/LiftCode.scala28
-rw-r--r--test/files/run/t5258a.check1
-rw-r--r--test/files/run/t5258a.scala14
-rw-r--r--test/pending/run/t5258b.check1
-rw-r--r--test/pending/run/t5258b.scala15
-rw-r--r--test/pending/run/t5258c.check1
-rw-r--r--test/pending/run/t5258c.scala15
9 files changed, 84 insertions, 10 deletions
diff --git a/src/compiler/scala/reflect/internal/Constants.scala b/src/compiler/scala/reflect/internal/Constants.scala
index 9c4b2b2245..c328cc49cb 100644
--- a/src/compiler/scala/reflect/internal/Constants.scala
+++ b/src/compiler/scala/reflect/internal/Constants.scala
@@ -45,7 +45,7 @@ trait Constants extends api.Constants {
case x: Char => CharTag
case x: Type => ClassTag
case x: Symbol => EnumTag
- case _ => throw new Error("bad constant value: " + value)
+ case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
}
def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue
diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala
index 23b443919a..4f5b28d370 100644
--- a/src/compiler/scala/reflect/internal/Importers.scala
+++ b/src/compiler/scala/reflect/internal/Importers.scala
@@ -145,8 +145,8 @@ trait Importers { self: SymbolTable =>
PolyType(tparams map importSymbol, importType(restpe))
case from.NullaryMethodType(restpe) =>
NullaryMethodType(importType(restpe))
- case from.ConstantType(from.Constant(value)) =>
- ConstantType(Constant(value))
+ case from.ConstantType(constant @ from.Constant(_)) =>
+ ConstantType(importConstant(constant))
case from.SuperType(thistpe, supertpe) =>
SuperType(importType(thistpe), importType(supertpe))
case from.TypeBounds(lo, hi) =>
@@ -194,8 +194,8 @@ trait Importers { self: SymbolTable =>
})
def importAnnotArg(arg: from.ClassfileAnnotArg): ClassfileAnnotArg = arg match {
- case from.LiteralAnnotArg(from.Constant(value)) =>
- LiteralAnnotArg(Constant(value))
+ case from.LiteralAnnotArg(constant @ from.Constant(_)) =>
+ LiteralAnnotArg(importConstant(constant))
case from.ArrayAnnotArg(args) =>
ArrayAnnotArg(args map importAnnotArg)
case from.ScalaSigBytes(bytes) =>
@@ -303,8 +303,8 @@ trait Importers { self: SymbolTable =>
case _ =>
new Ident(importName(name))
}
- case from.Literal(from.Constant(value)) =>
- new Literal(Constant(value))
+ case from.Literal(constant @ from.Constant(_)) =>
+ new Literal(importConstant(constant))
case from.TypeTree() =>
new TypeTree()
case from.Annotated(annot, arg) =>
@@ -339,5 +339,10 @@ trait Importers { self: SymbolTable =>
def importRefTree(tree: from.RefTree): RefTree = importTree(tree).asInstanceOf[RefTree]
def importIdent(tree: from.Ident): Ident = importTree(tree).asInstanceOf[Ident]
def importCaseDef(tree: from.CaseDef): CaseDef = importTree(tree).asInstanceOf[CaseDef]
+ def importConstant(constant: from.Constant): Constant = new Constant(constant.tag match {
+ case ClassTag => importType(constant.value.asInstanceOf[from.Type])
+ case EnumTag => importSymbol(constant.value.asInstanceOf[from.Symbol])
+ case _ => constant.value
+ })
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
index c5475fa0f2..f1182fc2a9 100644
--- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala
+++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
@@ -129,7 +129,13 @@ abstract class LiftCode extends Transform with TypingTransformers {
if (reifyCopypaste) printCopypaste(result)
result
}
- } finally printTypings = saved
+ } catch {
+ case ex: ReifierError =>
+ unit.error(ex.pos, ex.msg)
+ tree
+ } finally {
+ printTypings = saved
+ }
case _ =>
super.transform(tree)
}
@@ -396,6 +402,10 @@ abstract class LiftCode extends Transform with TypingTransformers {
if (thereAreOnlyTTs && ttsAreNotEssential) reifyTree(hk) else reifyProduct(ta)
case global.emptyValDef =>
mirrorSelect(nme.emptyValDef)
+ case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) =>
+ CannotReifyClassOfBoundType(tree, tpe)
+ case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym =>
+ CannotReifyClassOfBoundEnum(tree, constant.tpe)
case _ =>
if (tree.isDef)
boundSyms += tree.symbol
@@ -494,8 +504,20 @@ abstract class LiftCode extends Transform with TypingTransformers {
symDefs.toList ++ fillIns.toList
}
+ }
+
+ /** A throwable signalling a reification error */
+ class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) {
+ def this(msg: String) = this(NoPosition, msg)
+ }
+
+ def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = {
+ val msg = "cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe)
+ throw new ReifierError(tree.pos, msg)
+ }
- private def cannotReify(value: Any): Nothing =
- abort("don't know how to reify " + value + " of " + value.getClass)
+ def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = {
+ val msg = "cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe)
+ throw new ReifierError(tree.pos, msg)
}
}
diff --git a/test/files/run/t5258a.check b/test/files/run/t5258a.check
new file mode 100644
index 0000000000..4e0b2da04c
--- /dev/null
+++ b/test/files/run/t5258a.check
@@ -0,0 +1 @@
+int \ No newline at end of file
diff --git a/test/files/run/t5258a.scala b/test/files/run/t5258a.scala
new file mode 100644
index 0000000000..deabb8310f
--- /dev/null
+++ b/test/files/run/t5258a.scala
@@ -0,0 +1,14 @@
+import scala.tools.nsc.reporters._
+import scala.tools.nsc.Settings
+import reflect.runtime.Mirror.ToolBox
+
+object Test extends App {
+ val code = scala.reflect.Code.lift{
+ println(classOf[Int])
+ };
+
+ val reporter = new ConsoleReporter(new Settings)
+ val toolbox = new ToolBox(reporter)
+ val ttree = toolbox.typeCheck(code.tree)
+ toolbox.runExpr(ttree)
+} \ No newline at end of file
diff --git a/test/pending/run/t5258b.check b/test/pending/run/t5258b.check
new file mode 100644
index 0000000000..283b4225fb
--- /dev/null
+++ b/test/pending/run/t5258b.check
@@ -0,0 +1 @@
+TBI \ No newline at end of file
diff --git a/test/pending/run/t5258b.scala b/test/pending/run/t5258b.scala
new file mode 100644
index 0000000000..70cb4a7f4e
--- /dev/null
+++ b/test/pending/run/t5258b.scala
@@ -0,0 +1,15 @@
+import scala.tools.nsc.reporters._
+import scala.tools.nsc.Settings
+import reflect.runtime.Mirror.ToolBox
+
+object Test extends App {
+ val code = scala.reflect.Code.lift{
+ class C
+ println(classOf[C])
+ };
+
+ val reporter = new ConsoleReporter(new Settings)
+ val toolbox = new ToolBox(reporter)
+ val ttree = toolbox.typeCheck(code.tree)
+ toolbox.runExpr(ttree)
+} \ No newline at end of file
diff --git a/test/pending/run/t5258c.check b/test/pending/run/t5258c.check
new file mode 100644
index 0000000000..283b4225fb
--- /dev/null
+++ b/test/pending/run/t5258c.check
@@ -0,0 +1 @@
+TBI \ No newline at end of file
diff --git a/test/pending/run/t5258c.scala b/test/pending/run/t5258c.scala
new file mode 100644
index 0000000000..a93170d0d6
--- /dev/null
+++ b/test/pending/run/t5258c.scala
@@ -0,0 +1,15 @@
+import scala.tools.nsc.reporters._
+import scala.tools.nsc.Settings
+import reflect.runtime.Mirror.ToolBox
+
+object Test extends App {
+ val code = scala.reflect.Code.lift{
+ object E extends Enumeration { val foo, bar = Value }
+ println(E.foo)
+ };
+
+ val reporter = new ConsoleReporter(new Settings)
+ val toolbox = new ToolBox(reporter)
+ val ttree = toolbox.typeCheck(code.tree)
+ toolbox.runExpr(ttree)
+} \ No newline at end of file