Skip to content

Commit 4645c08

Browse files
committed
Rewrite classOf handling
So far, a miniphase took care of rewriting Predef.classOf to a class constant, but this means that `classOf` could survive in annotations (since they're not transformed) and needed to be handled by the backend. To simplify things, we take advantage of the constant folding done in the typer to directly replace `classOf` calls by a constant.
1 parent 6ab0e63 commit 4645c08

File tree

12 files changed

+36
-62
lines changed

12 files changed

+36
-62
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeHelpers.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,12 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
368368
case StringTag =>
369369
assert(const.value != null, const) // TODO this invariant isn't documented in `case class Constant`
370370
av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag
371-
case ClazzTag => av.visit(name, typeToTypeKind(const.typeValue)(bcodeStore)(innerClasesStore).toASMType)
371+
case ClazzTag => av.visit(name, typeToTypeKind(TypeErasure.erasure(const.typeValue))(bcodeStore)(innerClasesStore).toASMType)
372372
case EnumTag =>
373373
val edesc = innerClasesStore.typeDescriptor(const.tpe) // the class descriptor of the enumeration class.
374374
val evalue = const.symbolValue.javaSimpleName // value the actual enumeration value.
375375
av.visitEnum(name, edesc, evalue)
376376
}
377-
case t: TypeApply if (t.fun.symbol == defn.Predef_classOf) =>
378-
av.visit(name, typeToTypeKind(t.args.head.tpe.classSymbol.denot.info)(bcodeStore)(innerClasesStore).toASMType)
379377
case Ident(nme.WILDCARD) =>
380378
// An underscore argument indicates that we want to use the default value for this parameter, so do not emit anything
381379
case t: tpd.RefTree if t.symbol.denot.owner.isAllOf(JavaEnumTrait) =>

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ class Compiler {
6868
new CacheAliasImplicits, // Cache RHS of parameterless alias implicits
6969
new ByNameClosures, // Expand arguments to by-name parameters to closures
7070
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
71-
new ClassOf, // Expand `Predef.classOf` calls.
7271
new RefChecks) :: // Various checks mostly related to abstract members and overriding
7372
List(new ElimOpaque, // Turn opaque into normal aliases
7473
new TryCatchPatterns, // Compile cases in try/catch

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import typer.ConstFold
99
import reporting.trace
1010
import dotty.tools.dotc.transform.SymUtils._
1111
import Decorators._
12+
import Constants.Constant
1213

1314
import scala.annotation.tailrec
1415

@@ -396,7 +397,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
396397
case New(_) | Closure(_, _, _) =>
397398
Pure
398399
case TypeApply(fn, _) =>
399-
if (fn.symbol.is(Erased) || fn.symbol == defn.InternalQuoted_typeQuote) Pure else exprPurity(fn)
400+
if (fn.symbol.is(Erased) || fn.symbol == defn.InternalQuoted_typeQuote || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
400401
case Apply(fn, args) =>
401402
def isKnownPureOp(sym: Symbol) =
402403
sym.owner.isPrimitiveValueClass
@@ -517,6 +518,10 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
517518
def constToLiteral(tree: Tree)(implicit ctx: Context): Tree = {
518519
val tree1 = ConstFold(tree)
519520
tree1.tpe.widenTermRefExpr.dealias.normalized match {
521+
case ConstantType(Constant(_: Type)) if tree.isInstanceOf[Block] =>
522+
// We can't rewrite `{ class A; classOf[A] }` to `classOf[A]`, so we leave
523+
// blocks returning a class literal alone, even if they're idempotent.
524+
tree1
520525
case ConstantType(value) =>
521526
if (isIdempotentExpr(tree1)) Literal(value).withSpan(tree.span)
522527
else tree1 match {

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,25 +1154,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11541154
}
11551155
}
11561156

1157-
/** A tree that represents the class of the erasure of type `tp`. */
1158-
def clsOf(tp: Type)(implicit ctx: Context): Tree = {
1159-
def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_)
1160-
defn.scalaClassName(tp) match {
1161-
case tpnme.Boolean => TYPE(defn.BoxedBooleanModule)
1162-
case tpnme.Byte => TYPE(defn.BoxedByteModule)
1163-
case tpnme.Short => TYPE(defn.BoxedShortModule)
1164-
case tpnme.Char => TYPE(defn.BoxedCharModule)
1165-
case tpnme.Int => TYPE(defn.BoxedIntModule)
1166-
case tpnme.Long => TYPE(defn.BoxedLongModule)
1167-
case tpnme.Float => TYPE(defn.BoxedFloatModule)
1168-
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
1169-
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
1170-
case _ =>
1171-
if (ctx.erasedTypes || !tp.derivesFrom(defn.ArrayClass))
1157+
/** A tree that corresponds to `Predef.classOf[$tp]` in source */
1158+
def clsOf(tp: Type)(implicit ctx: Context): Tree =
1159+
if ctx.erasedTypes then
1160+
def TYPE(module: TermSymbol) = ref(module).select(nme.TYPE_)
1161+
defn.scalaClassName(tp) match
1162+
case tpnme.Boolean => TYPE(defn.BoxedBooleanModule)
1163+
case tpnme.Byte => TYPE(defn.BoxedByteModule)
1164+
case tpnme.Short => TYPE(defn.BoxedShortModule)
1165+
case tpnme.Char => TYPE(defn.BoxedCharModule)
1166+
case tpnme.Int => TYPE(defn.BoxedIntModule)
1167+
case tpnme.Long => TYPE(defn.BoxedLongModule)
1168+
case tpnme.Float => TYPE(defn.BoxedFloatModule)
1169+
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
1170+
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
1171+
case _ =>
11721172
Literal(Constant(TypeErasure.erasure(tp)))
1173-
else Literal(Constant(tp))
1174-
}
1175-
}
1173+
else
1174+
Literal(Constant(tp))
11761175

11771176
@tailrec
11781177
def sameTypes(trees: List[tpd.Tree], trees1: List[tpd.Tree]): Boolean =

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

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ object Erasure {
601601
if (tree.typeOpt.isRef(defn.UnitClass))
602602
tree.withType(tree.typeOpt)
603603
else if (tree.const.tag == Constants.ClazzTag)
604-
Literal(Constant(erasure(tree.const.typeValue)))
604+
clsOf(tree.const.typeValue)
605605
else
606606
super.typedLiteral(tree)
607607

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import java.lang.ArithmeticException
66
import ast._
77
import Trees._
88
import core._
9+
import Symbols._
910
import Types._
1011
import Constants._
1112
import Names._
@@ -31,6 +32,8 @@ object ConstFold {
3132
case ConstantType(x) => foldUnop(op, x)
3233
case _ => null
3334
}
35+
case TypeApply(_, List(targ)) if tree.symbol eq defn.Predef_classOf =>
36+
Constant(targ.tpe)
3437
case _ => null
3538
}
3639
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ trait TypeAssigner {
315315

316316
def assignType(tree: untpd.TypeApply, fn: Tree, args: List[Tree])(using Context): TypeApply = {
317317
def fail = tree.withType(errorType(err.takesNoParamsStr(fn, "type "), tree.sourcePos))
318-
fn.tpe.widen match {
318+
ConstFold(fn.tpe.widen match {
319319
case pt: TypeLambda =>
320320
tree.withType {
321321
val paramNames = pt.paramNames
@@ -381,7 +381,7 @@ trait TypeAssigner {
381381
case _ =>
382382
//println(i"bad type: $fn: ${fn.symbol} / ${fn.symbol.isType} / ${fn.symbol.info}") // DEBUG
383383
fail
384-
}
384+
})
385385
}
386386

387387
def assignType(tree: untpd.Typed, tpt: Tree)(using Context): Typed =

tests/semanticdb/expect/Advanced.expect.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object Test/*<-advanced::Test.*/ {
2626
val s2/*<-advanced::Test.s2.*/ = s/*->advanced::Test.s.*/.s2/*->advanced::Structural#s2().*/
2727
val s2x/*<-advanced::Test.s2x.*/ = /*->scala::reflect::Selectable.reflectiveSelectable().*/s/*->advanced::Test.s.*/.s2/*->advanced::Structural#s2().*//*->scala::Selectable#selectDynamic().*/.x
2828
val s3/*<-advanced::Test.s3.*/ = s/*->advanced::Test.s.*/.s3/*->advanced::Structural#s3().*/
29-
val s3x/*<-advanced::Test.s3x.*/ = /*->scala::reflect::Selectable.reflectiveSelectable().*/s/*->advanced::Test.s.*/.s3/*->advanced::Structural#s3().*//*->scala::Selectable#applyDynamic().*/.m/*->scala::reflect::ClassTag.apply().*//*->java::lang::Integer#TYPE.*/(???/*->scala::Predef.`???`().*/)
29+
val s3x/*<-advanced::Test.s3x.*/ = /*->scala::reflect::Selectable.reflectiveSelectable().*/s/*->advanced::Test.s.*/.s3/*->advanced::Structural#s3().*//*->scala::Selectable#applyDynamic().*/.m/*->scala::reflect::ClassTag.apply().*/(???/*->scala::Predef.`???`().*/)
3030

3131
val e/*<-advanced::Test.e.*/ = new Wildcards/*->advanced::Wildcards#*/
3232
val e1/*<-advanced::Test.e1.*/ = e/*->advanced::Test.e.*/.e1/*->advanced::Wildcards#e1().*/

tests/semanticdb/expect/Example.expect.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ object Example/*<-example::Example.*/ { self/*<-local0*/ =>
77
def main/*<-example::Example.main().*/(args/*<-example::Example.main().(args)*/: Array/*->scala::Array#*/[String/*->scala::Predef.String#*/]): Unit/*->scala::Unit#*/ = {
88
println/*->scala::Predef.println(+1).*/(1)
99
}
10-
val x/*<-example::Example.x.*/ = scala.reflect.classTag/*->scala::reflect::package.classTag().*/[Int/*->scala::Int#*/]/*->scala::reflect::ClassTag.apply().*//*->java::lang::Integer#TYPE.*/
10+
val x/*<-example::Example.x.*/ = scala.reflect.classTag/*->scala::reflect::package.classTag().*/[Int/*->scala::Int#*/]/*->scala::reflect::ClassTag.apply().*/
1111
}

0 commit comments

Comments
 (0)