Skip to content

Commit 610027b

Browse files
committed
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.
1 parent fbd5efe commit 610027b

File tree

9 files changed

+84
-10
lines changed

9 files changed

+84
-10
lines changed

src/compiler/scala/reflect/internal/Constants.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ trait Constants extends api.Constants {
4545
case x: Char => CharTag
4646
case x: Type => ClassTag
4747
case x: Symbol => EnumTag
48-
case _ => throw new Error("bad constant value: " + value)
48+
case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass)
4949
}
5050

5151
def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue

src/compiler/scala/reflect/internal/Importers.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ trait Importers { self: SymbolTable =>
145145
PolyType(tparams map importSymbol, importType(restpe))
146146
case from.NullaryMethodType(restpe) =>
147147
NullaryMethodType(importType(restpe))
148-
case from.ConstantType(from.Constant(value)) =>
149-
ConstantType(Constant(value))
148+
case from.ConstantType(constant @ from.Constant(_)) =>
149+
ConstantType(importConstant(constant))
150150
case from.SuperType(thistpe, supertpe) =>
151151
SuperType(importType(thistpe), importType(supertpe))
152152
case from.TypeBounds(lo, hi) =>
@@ -194,8 +194,8 @@ trait Importers { self: SymbolTable =>
194194
})
195195

196196
def importAnnotArg(arg: from.ClassfileAnnotArg): ClassfileAnnotArg = arg match {
197-
case from.LiteralAnnotArg(from.Constant(value)) =>
198-
LiteralAnnotArg(Constant(value))
197+
case from.LiteralAnnotArg(constant @ from.Constant(_)) =>
198+
LiteralAnnotArg(importConstant(constant))
199199
case from.ArrayAnnotArg(args) =>
200200
ArrayAnnotArg(args map importAnnotArg)
201201
case from.ScalaSigBytes(bytes) =>
@@ -303,8 +303,8 @@ trait Importers { self: SymbolTable =>
303303
case _ =>
304304
new Ident(importName(name))
305305
}
306-
case from.Literal(from.Constant(value)) =>
307-
new Literal(Constant(value))
306+
case from.Literal(constant @ from.Constant(_)) =>
307+
new Literal(importConstant(constant))
308308
case from.TypeTree() =>
309309
new TypeTree()
310310
case from.Annotated(annot, arg) =>
@@ -339,5 +339,10 @@ trait Importers { self: SymbolTable =>
339339
def importRefTree(tree: from.RefTree): RefTree = importTree(tree).asInstanceOf[RefTree]
340340
def importIdent(tree: from.Ident): Ident = importTree(tree).asInstanceOf[Ident]
341341
def importCaseDef(tree: from.CaseDef): CaseDef = importTree(tree).asInstanceOf[CaseDef]
342+
def importConstant(constant: from.Constant): Constant = new Constant(constant.tag match {
343+
case ClassTag => importType(constant.value.asInstanceOf[from.Type])
344+
case EnumTag => importSymbol(constant.value.asInstanceOf[from.Symbol])
345+
case _ => constant.value
346+
})
342347
}
343348
}

src/compiler/scala/tools/nsc/transform/LiftCode.scala

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,13 @@ abstract class LiftCode extends Transform with TypingTransformers {
129129
if (reifyCopypaste) printCopypaste(result)
130130
result
131131
}
132-
} finally printTypings = saved
132+
} catch {
133+
case ex: ReifierError =>
134+
unit.error(ex.pos, ex.msg)
135+
tree
136+
} finally {
137+
printTypings = saved
138+
}
133139
case _ =>
134140
super.transform(tree)
135141
}
@@ -396,6 +402,10 @@ abstract class LiftCode extends Transform with TypingTransformers {
396402
if (thereAreOnlyTTs && ttsAreNotEssential) reifyTree(hk) else reifyProduct(ta)
397403
case global.emptyValDef =>
398404
mirrorSelect(nme.emptyValDef)
405+
case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) =>
406+
CannotReifyClassOfBoundType(tree, tpe)
407+
case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym =>
408+
CannotReifyClassOfBoundEnum(tree, constant.tpe)
399409
case _ =>
400410
if (tree.isDef)
401411
boundSyms += tree.symbol
@@ -494,8 +504,20 @@ abstract class LiftCode extends Transform with TypingTransformers {
494504

495505
symDefs.toList ++ fillIns.toList
496506
}
507+
}
508+
509+
/** A throwable signalling a reification error */
510+
class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) {
511+
def this(msg: String) = this(NoPosition, msg)
512+
}
513+
514+
def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = {
515+
val msg = "cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe)
516+
throw new ReifierError(tree.pos, msg)
517+
}
497518

498-
private def cannotReify(value: Any): Nothing =
499-
abort("don't know how to reify " + value + " of " + value.getClass)
519+
def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = {
520+
val msg = "cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe)
521+
throw new ReifierError(tree.pos, msg)
500522
}
501523
}

test/files/run/t5258a.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int

test/files/run/t5258a.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.tools.nsc.reporters._
2+
import scala.tools.nsc.Settings
3+
import reflect.runtime.Mirror.ToolBox
4+
5+
object Test extends App {
6+
val code = scala.reflect.Code.lift{
7+
println(classOf[Int])
8+
};
9+
10+
val reporter = new ConsoleReporter(new Settings)
11+
val toolbox = new ToolBox(reporter)
12+
val ttree = toolbox.typeCheck(code.tree)
13+
toolbox.runExpr(ttree)
14+
}

test/pending/run/t5258b.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TBI

test/pending/run/t5258b.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.tools.nsc.reporters._
2+
import scala.tools.nsc.Settings
3+
import reflect.runtime.Mirror.ToolBox
4+
5+
object Test extends App {
6+
val code = scala.reflect.Code.lift{
7+
class C
8+
println(classOf[C])
9+
};
10+
11+
val reporter = new ConsoleReporter(new Settings)
12+
val toolbox = new ToolBox(reporter)
13+
val ttree = toolbox.typeCheck(code.tree)
14+
toolbox.runExpr(ttree)
15+
}

test/pending/run/t5258c.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TBI

test/pending/run/t5258c.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.tools.nsc.reporters._
2+
import scala.tools.nsc.Settings
3+
import reflect.runtime.Mirror.ToolBox
4+
5+
object Test extends App {
6+
val code = scala.reflect.Code.lift{
7+
object E extends Enumeration { val foo, bar = Value }
8+
println(E.foo)
9+
};
10+
11+
val reporter = new ConsoleReporter(new Settings)
12+
val toolbox = new ToolBox(reporter)
13+
val ttree = toolbox.typeCheck(code.tree)
14+
toolbox.runExpr(ttree)
15+
}

0 commit comments

Comments
 (0)