Skip to content

Commit f2a99cd

Browse files
committed
Fix scala#3947: Support lifting of java.lang.Class
1 parent d5ee92b commit f2a99cd

File tree

6 files changed

+170
-8
lines changed

6 files changed

+170
-8
lines changed

compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import dotty.tools.dotc.core.Flags._
1010
import dotty.tools.dotc.core.StdNames._
1111
import dotty.tools.dotc.core.NameKinds
1212
import dotty.tools.dotc.core.Symbols._
13+
import dotty.tools.dotc.core.Types.Type
1314
import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString}
1415

1516
import scala.quoted.Types._
@@ -33,7 +34,11 @@ object PickledQuotes {
3334
/** Transform the expression into its fully spliced Tree */
3435
def quotedExprToTree(expr: quoted.Expr[_])(implicit ctx: Context): Tree = expr match {
3536
case expr: TastyExpr[_] => unpickleExpr(expr)
36-
case expr: LiftedExpr[_] => Literal(Constant(expr.value))
37+
case expr: LiftedExpr[_] =>
38+
expr.value match {
39+
case value: Class[_] => ref(defn.Predef_classOf).appliedToType(classToType(value))
40+
case value => Literal(Constant(value))
41+
}
3742
case expr: TreeExpr[Tree] @unchecked => expr.tree
3843
case expr: FunctionAppliedTo[_, _] =>
3944
functionAppliedTo(quotedExprToTree(expr.f), quotedExprToTree(expr.x))
@@ -154,4 +159,25 @@ object PickledQuotes {
154159
}
155160
Block(x1 :: Nil, rec(f))
156161
}
162+
163+
private def classToType(clazz: Class[_])(implicit ctx: Context): Type = {
164+
if (clazz == classOf[Boolean]) defn.BooleanType
165+
else if (clazz == classOf[Byte]) defn.ByteType
166+
else if (clazz == classOf[Char]) defn.CharType
167+
else if (clazz == classOf[Short]) defn.ShortType
168+
else if (clazz == classOf[Int]) defn.IntType
169+
else if (clazz == classOf[Long]) defn.LongType
170+
else if (clazz == classOf[Float]) defn.FloatType
171+
else if (clazz == classOf[Double]) defn.DoubleType
172+
else if (clazz == classOf[Unit]) defn.UnitType
173+
else if (!clazz.isMemberClass) ctx.getClassIfDefined(clazz.getCanonicalName).typeRef
174+
else {
175+
val name = clazz.getSimpleName.toTypeName
176+
val enclosing = classToType(clazz.getEnclosingClass)
177+
if (enclosing.member(name).exists) enclosing.select(name)
178+
else {
179+
enclosing.classSymbol.companionModule.termRef.select(name)
180+
}
181+
}
182+
}
157183
}

compiler/src/dotty/tools/dotc/quoted/Toolbox.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ object Toolbox {
2929

3030
def show(expr: Expr[T]): String = expr match {
3131
case expr: LiftedExpr[T] =>
32-
implicit val ctx = new QuoteDriver().initCtx
33-
if (showSettings.compilerArgs.contains("-color:never"))
34-
ctx.settings.color.update("never")
35-
val printer = new RefinedPrinter(ctx)
36-
if (expr.value == BoxedUnit.UNIT) "()"
37-
else printer.toText(Literal(Constant(expr.value))).mkString(Int.MaxValue, false)
32+
expr.value match {
33+
case value: Class[_] => s"classOf[${value.getCanonicalName}]"
34+
case value if value == BoxedUnit.UNIT => "()"
35+
case value =>
36+
implicit val ctx = new QuoteDriver().initCtx
37+
if (showSettings.compilerArgs.contains("-color:never"))
38+
ctx.settings.color.update("never")
39+
val printer = new RefinedPrinter(ctx)
40+
printer.toText(Literal(Constant(value))).mkString(Int.MaxValue, false)
41+
}
3842
case _ => new QuoteDriver().show(expr, showSettings)
3943
}
4044

library/src/scala/quoted/Liftable.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ object Liftable {
2525
implicit def DoubleIsLiftable: Liftable[Double] = (x: Double) => liftedExpr(x)
2626

2727
implicit def StringIsLiftable: Liftable[String] = (x: String) => liftedExpr(x)
28+
29+
implicit def ClassIsLiftable[T]: Liftable[Class[T]] = (x: Class[T]) => liftedExpr(x)
2830
}

library/src/scala/runtime/quoted/Unpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Unpickler {
1818
def unpickleExpr[T](repr: Pickled, args: Seq[Any]): Expr[T] = new TastyExpr[T](repr, args)
1919

2020
/** Lift the `value` to an `Expr` tree.
21-
* Values can only be of type Boolean, Byte, Short, Char, Int, Long, Float, Double, Unit, String or Null.
21+
* Values can only be of type Boolean, Byte, Short, Char, Int, Long, Float, Double, Unit, String, Null or Class.
2222
*/
2323
def liftedExpr[T](value: T): LiftedExpr[T] = new LiftedExpr[T](value)
2424

tests/run-with-compiler/i3947.check

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
classOf[Object].getCanonicalName()
3+
java.lang.Object
4+
5+
classOf[Object].getCanonicalName()
6+
java.lang.Object
7+
8+
classOf[Object].getCanonicalName()
9+
java.lang.Object
10+
11+
classOf[Object].getCanonicalName()
12+
java.lang.Object
13+
14+
classOf[Boolean].getCanonicalName()
15+
boolean
16+
17+
classOf[Byte].getCanonicalName()
18+
byte
19+
20+
classOf[Char].getCanonicalName()
21+
char
22+
23+
classOf[Short].getCanonicalName()
24+
short
25+
26+
classOf[Int].getCanonicalName()
27+
int
28+
29+
classOf[Long].getCanonicalName()
30+
long
31+
32+
classOf[Float].getCanonicalName()
33+
float
34+
35+
classOf[Double].getCanonicalName()
36+
double
37+
38+
classOf[Unit].getCanonicalName()
39+
void
40+
41+
classOf[scala.runtime.Null$].getCanonicalName()
42+
scala.runtime.Null$
43+
44+
classOf[scala.runtime.Nothing$].getCanonicalName()
45+
scala.runtime.Nothing$
46+
47+
classOf[String].getCanonicalName()
48+
java.lang.String
49+
50+
classOf[Foo].getCanonicalName()
51+
Foo
52+
53+
classOf[Foo#Bar].getCanonicalName()
54+
Foo.Bar
55+
56+
classOf[Foo.Baz].getCanonicalName()
57+
Foo.Baz
58+
59+
classOf[foo.Foo].getCanonicalName()
60+
foo.Foo
61+
62+
classOf[foo.Foo#Bar].getCanonicalName()
63+
foo.Foo.Bar
64+
65+
classOf[foo.Foo.Baz].getCanonicalName()
66+
foo.Foo.Baz

tests/run-with-compiler/i3947.scala

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
import scala.quoted._
3+
import dotty.tools.dotc.quoted.Toolbox._
4+
5+
object Test {
6+
7+
def main(args: Array[String]): Unit = {
8+
9+
def test[T](clazz: java.lang.Class[T]): Unit = {
10+
val lclazz = clazz.toExpr
11+
val name = '{ (~clazz.toExpr).getCanonicalName }
12+
println()
13+
println(name.show)
14+
println(name.run)
15+
}
16+
17+
// classOf[Object]
18+
test(classOf[Object])
19+
test(classOf[Any])
20+
test(classOf[AnyRef])
21+
test(classOf[AnyVal])
22+
23+
// primitives
24+
test(classOf[Boolean])
25+
test(classOf[Byte])
26+
test(classOf[Char])
27+
test(classOf[Short])
28+
test(classOf[Int])
29+
test(classOf[Long])
30+
test(classOf[Float])
31+
test(classOf[Double])
32+
test(classOf[Unit])
33+
test(classOf[Null])
34+
test(classOf[Nothing])
35+
36+
test(classOf[String])
37+
38+
test(classOf[Foo])
39+
test(classOf[Foo#Bar])
40+
test(classOf[Foo.Baz])
41+
42+
test(classOf[foo.Foo])
43+
test(classOf[foo.Foo#Bar])
44+
test(classOf[foo.Foo.Baz])
45+
}
46+
47+
}
48+
49+
class Foo {
50+
class Bar
51+
}
52+
53+
object Foo {
54+
class Baz
55+
}
56+
57+
package foo {
58+
class Foo {
59+
class Bar
60+
}
61+
object Foo {
62+
class Baz
63+
}
64+
}

0 commit comments

Comments
 (0)