Skip to content

Commit b6af494

Browse files
committed
Proper handling of primitive getClass corner case
After the previous commit, t5568 started crashing, but it turns out that it had always been wrong: 1.asInstanceOf[Int & AnyRef].getClass is supposed to return classOf[Integer] but actually returns classOf[Int], when this test was imported from scalac, the checkfile was changed to make the test pass instead of aligining the compiler behavior with scalac. This commit fixes that: by dropping the `getClass` overload defined in primitive value classes which confuses the compiler, see `hasProblematicGetClass`.
1 parent 946dba1 commit b6af494

File tree

4 files changed

+48
-10
lines changed

4 files changed

+48
-10
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,19 @@ object desugar {
460460
case tree: MemberDef => Ident(tree.name.toTermName) :: Nil
461461
case PatDef(_, ids: List[Ident] @ unchecked, _, _) => ids
462462
}
463-
val stats = impl.body.map(expandConstructor)
463+
464+
val stats0 = impl.body.map(expandConstructor)
465+
val stats =
466+
if (ctx.owner eq defn.ScalaPackageClass) && defn.hasProblematicGetClass(className) then
467+
stats0.filterConserve {
468+
case ddef: DefDef =>
469+
ddef.name ne nme.getClass_
470+
case _ =>
471+
true
472+
}
473+
else
474+
stats0
475+
464476
if (isEnum) {
465477
val (enumCases, enumStats) = stats.partition(DesugarEnums.isEnumCase)
466478
if (enumCases.isEmpty)

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,27 @@ class Definitions {
13091309
else parents
13101310
}
13111311

1312+
private val HasProblematicGetClass: Set[Name] = Set(
1313+
tpnme.AnyVal, tpnme.Byte, tpnme.Short, tpnme.Char, tpnme.Int, tpnme.Long, tpnme.Float, tpnme.Double,
1314+
tpnme.Unit, tpnme.Boolean)
1315+
1316+
/** When typing a primitive value class or AnyVal, we ignore the `getClass`
1317+
* member: it's supposed to be an override of the `getClass` defined on `Any`,
1318+
* but in dotty `Any#getClass` is polymorphic so it ends up being an overload.
1319+
* This is especially problematic because it means that when writing:
1320+
*
1321+
* 1.asInstanceOf[Int & AnyRef].getClass
1322+
*
1323+
* the `getClass` that returns `Class[Int]` defined in Int can be selected,
1324+
* but this call is specified to return `classOf[Integer]`, see
1325+
* tests/run/t5568.scala.
1326+
*
1327+
* FIXME: remove all the `getClass` methods defined in the standard library
1328+
* so we don't have to hot-patch it like this.
1329+
*/
1330+
def hasProblematicGetClass(className: Name): Boolean =
1331+
HasProblematicGetClass.contains(className)
1332+
13121333
/** Is synthesized symbol with alphanumeric name allowed to be used as an infix operator? */
13131334
def isInfix(sym: Symbol)(implicit ctx: Context): Boolean =
13141335
(sym eq Object_eq) || (sym eq Object_ne)

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,12 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
187187
val savedIndex = readIndex
188188
readIndex = index(i)
189189
val sym = readSymbol()
190-
entries(i) = sym
191-
sym.infoOrCompleter match {
192-
case info: ClassUnpickler => info.init()
193-
case _ =>
194-
}
190+
if sym.exists then
191+
entries(i) = sym
192+
sym.infoOrCompleter match {
193+
case info: ClassUnpickler => info.init()
194+
case _ =>
195+
}
195196
readIndex = savedIndex
196197
}
197198
i += 1
@@ -438,6 +439,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
438439
var name = at(nameref, () => readName()(ctx))
439440
val owner = readSymbolRef()
440441

442+
if (name eq nme.getClass_) && defn.hasProblematicGetClass(owner.name) then
443+
// skip this member
444+
return NoSymbol
445+
441446
var flags = unpickleScalaFlags(readLongNat(), name.isTypeName)
442447

443448
name = name.adjustIfModuleClass(flags)

tests/run/t5568.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
void
22
int
3-
void
4-
void
5-
int
6-
int
3+
class scala.runtime.BoxedUnit
4+
class scala.runtime.BoxedUnit
5+
class java.lang.Integer
6+
class java.lang.Integer
77
5
88
5
99
5

0 commit comments

Comments
 (0)