diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala index aeaf6f11543b..8c5fb61c9da7 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala @@ -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('<') @@ -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 @@ -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 diff --git a/compiler/test/dotty/tools/AnnotationsTests.scala b/compiler/test/dotty/tools/AnnotationsTests.scala index a197ca4bc94e..e7fc1242517c 100644 --- a/compiler/test/dotty/tools/AnnotationsTests.scala +++ b/compiler/test/dotty/tools/AnnotationsTests.scala @@ -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") } }