Skip to content

Commit 946dba1

Browse files
committed
Rewrite getClass handling
Previously, getClass was implemented as a miniphase, but that miniphase completely neglected to preserve potential side-effects in the prefix of the call. Instead of doing this manually in the miniphase, we extend our constant folding logic to recognize getClass calls, this simplifies things since constant folding already knows how to deal with side-effects.
1 parent b814e77 commit 946dba1

File tree

4 files changed

+31
-39
lines changed

4 files changed

+31
-39
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ class Compiler {
108108
List(new Constructors, // Collect initialization code in primary constructors
109109
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
110110
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
111-
new Instrumentation, // Count closure allocations under -Yinstrument-closures
112-
new GetClass) :: // Rewrites getClass calls on primitive types.
111+
new Instrumentation) :: // Count closure allocations under -Yinstrument-closures
113112
List(new LinkScala2Impls, // Redirect calls to trait methods defined by Scala 2.x, so that they now go to
114113
new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
115114
// Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here

compiler/src/dotty/tools/dotc/transform/GetClass.scala

Lines changed: 0 additions & 33 deletions
This file was deleted.

compiler/src/dotty/tools/dotc/typer/ConstFold.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Constants._
1212
import Names._
1313
import StdNames._
1414
import Contexts._
15+
import transform.TypeUtils._
1516

1617
object ConstFold {
1718

@@ -28,10 +29,13 @@ object ConstFold {
2829
case _ => null
2930
case _ => null
3031
case Select(xt, op) =>
31-
xt.tpe.widenTermRefExpr match {
32-
case ConstantType(x) => foldUnop(op, x)
33-
case _ => null
34-
}
32+
if (op eq nme.getClass_) && xt.tpe.widen.isPrimitiveValueType then
33+
Constant(xt.tpe.widen)
34+
else
35+
xt.tpe.widenTermRefExpr match {
36+
case ConstantType(x) => foldUnop(op, x)
37+
case _ => null
38+
}
3539
case TypeApply(_, List(targ)) if tree.symbol eq defn.Predef_classOf =>
3640
Constant(targ.tpe)
3741
case _ => null

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,28 @@ class TestBCode extends DottyBytecodeTest {
822822
}
823823
}
824824

825+
@Test
826+
def getClazz: Unit = {
827+
val source = """
828+
|class Foo {
829+
| def sideEffect(): Int = { println("hi"); 1 }
830+
| def before: Class[Int] = sideEffect().getClass
831+
| def after: Class[Int] = { sideEffect(); classOf[Int] }
832+
|}
833+
""".stripMargin
834+
835+
checkBCode(source) { dir =>
836+
val clsIn = dir.lookupName("Foo.class", directory = false).input
837+
val clsNode = loadClassNode(clsIn)
838+
val before = instructionsFromMethod(getMethod(clsNode, "before"))
839+
val after = instructionsFromMethod(getMethod(clsNode, "after"))
840+
841+
assert(before == after,
842+
"`before1` was not translated to the same bytecode as `after`\n" +
843+
diffInstructions(before, after))
844+
}
845+
}
846+
825847
@Test
826848
def invocationReceivers(): Unit = {
827849
import Opcodes._

0 commit comments

Comments
 (0)