diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 41993d9fb578..1fc7ee5d22a8 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -602,7 +602,9 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst else if (tp.isRepeatedParam) apply(tp.translateFromRepeated(toArray = sourceLanguage.isJava)) else if (semiEraseVCs && isDerivedValueClass(tycon.classSymbol)) eraseDerivedValueClass(tp) else apply(tp.translucentSuperType) - case _: TermRef | _: ThisType => + case tp: TermRef => + this(underlyingOfTermRef(tp)) + case _: ThisType => this(tp.widen) case SuperType(thistpe, supertpe) => SuperType(this(thistpe), this(supertpe)) @@ -687,6 +689,19 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst tp } + /** Widen term ref, skipping any `()` parameter of an eventual getter. Used to erase a TermRef. + * Since getters are introduced after erasure, one would think that erasing a TermRef + * could just use `widen`. However, it's possible that the TermRef got read from a class + * file after Getters (i.e. in the backend). In that case, the reference will not get + * an earlier denotation even when time travelling forward to erasure. Hence, we + * need to take the extra precaution of going from nullary method types to their resuls. + * A test case where this is needed is pos/i15649.scala, which fails non-deterministically + * if `underlyingOfTermRef` is replaced by `widen`. + */ + private def underlyingOfTermRef(tp: TermRef)(using Context) = tp.widen match + case tpw @ MethodType(Nil) if tp.symbol.isGetter => tpw.resultType + case tpw => tpw + private def eraseArray(tp: Type)(using Context) = { val defn.ArrayOf(elemtp) = tp: @unchecked if (isGenericArrayElement(elemtp, isScala2 = sourceLanguage.isScala2)) defn.ObjectType @@ -832,7 +847,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst case JavaArrayType(elem) => sigName(elem) ++ "[]" case tp: TermRef => - sigName(tp.widen) + sigName(underlyingOfTermRef(tp)) case ExprType(rt) => sigName(defn.FunctionOf(Nil, rt)) case tp: TypeVar => diff --git a/tests/pos/i15649.scala b/tests/pos/i15649.scala new file mode 100644 index 000000000000..8c82c8db39a8 --- /dev/null +++ b/tests/pos/i15649.scala @@ -0,0 +1,11 @@ +trait ConfigSourceModule: + object ConfigSource: + class R + +object M extends ConfigSourceModule + +object Foo: + implicit class FromConfigSource(c: M.ConfigSource.type) + +object FooBar: // problem disappears if we rename as `Bar` + def foo: M.ConfigSource.R = new M.ConfigSource.R // problem disappears if we use `???` as rhs \ No newline at end of file