aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-07-27 23:26:26 +0200
committerDmitry Petrashko <dark@d-d.me>2015-07-27 23:26:26 +0200
commit056e1246c9dc365bd37627923b999a80a57ca0f9 (patch)
tree28d95f59b223290c035ed2f716840c19f6b73872
parentcf17b73cc02daf514f6d5499fd7a5562fc93349e (diff)
parentd24c6945963198566cd8e97e6bcacf6ebe2127dc (diff)
downloaddotty-056e1246c9dc365bd37627923b999a80a57ca0f9.tar.gz
dotty-056e1246c9dc365bd37627923b999a80a57ca0f9.tar.bz2
dotty-056e1246c9dc365bd37627923b999a80a57ca0f9.zip
Merge pull request #734 from alexander-myltsev/add-getclass
Implement getClass
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/transform/GetClass.scala49
-rw-r--r--tests/run/getclass.check26
-rw-r--r--tests/run/getclass.scala41
4 files changed, 118 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 75b790861..76cf10428 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -70,7 +70,8 @@ class Compiler {
new LinkScala2ImplClasses,
new CapturedVars, // capturedVars has a transformUnit: no phases should introduce local mutable vars here
new Constructors,
- new FunctionalInterfaces),
+ new FunctionalInterfaces,
+ new GetClass), // getClass transformation should be applied to specialized methods
List(new LambdaLift, // in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
new ElimStaticThis,
new Flatten,
diff --git a/src/dotty/tools/dotc/transform/GetClass.scala b/src/dotty/tools/dotc/transform/GetClass.scala
new file mode 100644
index 000000000..0545133da
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/GetClass.scala
@@ -0,0 +1,49 @@
+package dotty.tools.dotc
+package transform
+
+import ast.tpd
+import core.Contexts.Context
+import core.StdNames.nme
+import core.Symbols.TermSymbol
+import core.Phases.Phase
+import TreeTransforms.{MiniPhaseTransform, TransformerInfo}
+
+/** Rewrite `getClass` calls as follow:
+ *
+ * For every instance of primitive class C whose boxed class is called B:
+ * instanceC.getClass -> B.TYPE
+ * For every instance of non-primitive class D:
+ * instanceD.getClass -> instanceD.getClass
+ */
+class GetClass extends MiniPhaseTransform {
+ import tpd._
+
+ override def phaseName: String = "getClass"
+
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ import ast.Trees._
+
+ tree match {
+ case Apply(Select(qual, nme.getClass_), Nil) =>
+ val defn = ctx.definitions
+ val claz = qual.tpe.classSymbol
+
+ def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_).ensureConforms(tree.tpe)
+ claz match {
+ case defn.BooleanClass => TYPE(defn.BoxedBooleanModule)
+ case defn.ByteClass => TYPE(defn.BoxedByteModule)
+ case defn.ShortClass => TYPE(defn.BoxedShortModule)
+ case defn.CharClass => TYPE(defn.BoxedCharModule)
+ case defn.IntClass => TYPE(defn.BoxedIntModule)
+ case defn.LongClass => TYPE(defn.BoxedLongModule)
+ case defn.FloatClass => TYPE(defn.BoxedFloatModule)
+ case defn.DoubleClass => TYPE(defn.BoxedDoubleModule)
+ case defn.UnitClass => TYPE(defn.BoxedVoidModule)
+ case _ => tree
+ }
+ case _ => tree
+ }
+ }
+}
diff --git a/tests/run/getclass.check b/tests/run/getclass.check
new file mode 100644
index 000000000..9d88762f4
--- /dev/null
+++ b/tests/run/getclass.check
@@ -0,0 +1,26 @@
+Value types:
+void
+boolean
+byte
+short
+char
+int
+long
+float
+double
+
+Class types:
+class SomeClass
+class ValueClass
+class scala.collection.immutable.$colon$colon
+class scala.Tuple2
+
+Arrays:
+class [Lscala.runtime.BoxedUnit;
+class [I
+class [D
+class [Lscala.collection.immutable.List;
+
+Functions:
+class Test$$$Lambda$1
+class Test$$$Lambda$2
diff --git a/tests/run/getclass.scala b/tests/run/getclass.scala
new file mode 100644
index 000000000..7e6430a53
--- /dev/null
+++ b/tests/run/getclass.scala
@@ -0,0 +1,41 @@
+class ValueClass(val i: Integer) extends AnyVal
+class SomeClass
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val cls: Predef.Class[_] = new SomeClass().getClass
+ val valCls: Predef.Class[_] = new ValueClass(1).getClass
+ val iCls: Class[Int] = 1.getClass
+ val f1: Function2[Int, Int, Unit] = (a: Int, b: Int) => println(a + b)
+ val f2: Function1[Int, Boolean] = (a: Int) => a % 2 == 0
+
+ println("Value types:")
+ println(().getClass)
+ println(true.getClass)
+ println(1.asInstanceOf[Byte].getClass)
+ println(1.asInstanceOf[Short].getClass)
+ println('a'.getClass)
+ println(1.getClass)
+ println(1L.getClass)
+ println(1f.getClass)
+ println(1d.getClass)
+
+ println("\nClass types:")
+ println(new SomeClass().getClass)
+ println(new ValueClass(1).getClass)
+ println(List(Array(1f)).getClass)
+ println(("a", Map(1 -> "b")).getClass)
+
+ println("\nArrays:")
+ println(Array(()).getClass)
+ println(Array(1).getClass)
+ println(Array(1d).getClass)
+ println(Array(List("1")).getClass)
+
+ println("\nFunctions:")
+ // FunctionN.getClass.toString has form of "class Test$$$Lambda$N/1349414238",
+ // but number (1349414238) depends on environment
+ println(f1.getClass.toString.takeWhile(_ != '/'))
+ println(f2.getClass.toString.takeWhile(_ != '/'))
+ }
+}