Skip to content

Fix #10888: Avoid A.this.B for Java inner classes #11006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -349,13 +349,19 @@ class ClassfileParser(
val tag = sig(index); index += 1
(tag: @switch) match {
case 'L' =>
def processInner(tp: Type): Type = tp match {
case tp: TypeRef if !tp.symbol.owner.is(Flags.ModuleClass) =>
TypeRef(processInner(tp.prefix.widen), tp.symbol.asType)
case _ =>
tp
}
def processClassType(tp: Type): Type = tp match {
/** A type representation where inner classes become `A#B` instead of `A.this.B` (like with `typeRef`)
*
* Note: the symbol must not be nested in a generic class.
*/
def innerType(symbol: Symbol): Type =
if symbol.is(Flags.Package) then
symbol.thisType
else if symbol.isType then
TypeRef(innerType(symbol.owner), symbol)
else
throw new RuntimeException("unexpected term symbol " + symbol)

def processTypeArgs(tp: Type): Type = tp match {
case tp: TypeRef =>
if (sig(index) == '<') {
accept('<')
Expand Down Expand Up @@ -388,13 +394,13 @@ class ClassfileParser(
}

val classSym = classNameToSymbol(subName(c => c == ';' || c == '<'))
val classTpe = if (classSym eq defn.ObjectClass) defn.FromJavaObjectType else classSym.typeRef
var tpe = processClassType(processInner(classTpe))
val classTpe = if (classSym eq defn.ObjectClass) defn.FromJavaObjectType else innerType(classSym)
var tpe = processTypeArgs(classTpe)
while (sig(index) == '.') {
accept('.')
val name = subName(c => c == ';' || c == '<' || c == '.').toTypeName
val clazz = tpe.member(name).symbol
tpe = processClassType(processInner(TypeRef(tpe, clazz)))
val tp = tpe.select(name)
tpe = processTypeArgs(tp)
}
accept(';')
tpe
Expand Down Expand Up @@ -432,15 +438,15 @@ class ClassfileParser(
paramtypes += {
if isRepeatedParam(index) then
index += 1
val elemType = sig2type(tparams, skiptvs)
val elemType = sig2type(tparams, skiptvs = false)
// `ElimRepeated` is responsible for correctly erasing this.
defn.RepeatedParamType.appliedTo(elemType)
else
sig2type(tparams, skiptvs)
sig2type(tparams, skiptvs = false)
}

index += 1
val restype = sig2type(tparams, skiptvs)
val restype = sig2type(tparams, skiptvs = false)
JavaMethodType(paramnames.toList, paramtypes.toList, restype)
case 'T' =>
val n = subName(';'.==).toTypeName
Expand Down
11 changes: 9 additions & 2 deletions compiler/test/dotty/tools/AnnotationsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ class AnnotationsTest:
val arrayOfString = defn.ArrayType.appliedTo(List(defn.StringType))

atPhase(erasurePhase.next) {
val annot = cls.getAnnotation(annotCls)
// Even though we're forcing the annotation after erasure,
// the typed trees should be unerased, so the type of
// the annotation argument should be `arrayOfString` and
// not a `JavaArrayType`.
val annot = cls.getAnnotation(annotCls)
val arg = annot.get.argument(0).get
assert(arg.tpe.isInstanceOf[AppliedType] && arg.tpe =:= arrayOfString,

// If we run the type check after erasure, we will have
// `Array[String] =:= Array[String]` being false.
// The reason is that in `TypeComparer.compareAppliedType2` we have
// `tycon2.typeParams == Nil` after erasure, thus always get false.
val res = atPhase(typerPhase) { arrayOfString =:= arg.tpe }

assert(arg.tpe.isInstanceOf[AppliedType] && res,
s"Argument $arg had type:\n${arg.tpe}\nbut expected type:\n$arrayOfString")
}
}
Expand Down