Skip to content

Commit e4f60a4

Browse files
committed
Ensure names used in signatures are stable
Signatures should not change before erasure, but some phases before erasure can change the owner of a definition, which can change their full name and therefore any signature which refers to these names. This commit fixes this by ensuring we always use the initial symbol to compute signatures before erasure. The check for signature consistency in TreeChecker was also improved as it wasn't able to catch this issue before due to signature caching hiding the issue.
1 parent 31879e5 commit e4f60a4

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,16 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
605605
if (defn.isSyntheticFunctionClass(sym))
606606
sigName(defn.erasedFunctionType(sym))
607607
else
608-
normalizeClass(sym.asClass).fullName.asTypeName
608+
val cls = normalizeClass(sym.asClass)
609+
val fullName =
610+
if !ctx.erasedTypes then
611+
// It's important to use the initial symbol to compute the full name
612+
// because the current symbol might have a different name or owner
613+
// and signatures are required to be stable before erasure.
614+
cls.initial.fullName
615+
else
616+
cls.fullName
617+
fullName.asTypeName
609618
case tp: AppliedType =>
610619
val sym = tp.tycon.typeSymbol
611620
sigName( // todo: what about repeatedParam?

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,7 +1900,7 @@ object Types {
19001900
* or if there is none, the signature of the symbol. Signatures are always
19011901
* computed before erasure, since some symbols change their signature at erasure.
19021902
*/
1903-
protected def computeSignature(implicit ctx: Context): Signature =
1903+
protected[dotc] def computeSignature(implicit ctx: Context): Signature =
19041904
val lastd = lastDenotation
19051905
if lastd != null then sigFromDenot(lastd)
19061906
else if ctx.erasedTypes then computeSignature(using ctx.withPhase(ctx.erasurePhase))
@@ -3064,7 +3064,7 @@ object Types {
30643064
protected var mySignature: Signature = _
30653065
protected var mySignatureRunId: Int = NoRunId
30663066

3067-
protected def computeSignature(implicit ctx: Context): Signature
3067+
protected[dotc] def computeSignature(implicit ctx: Context): Signature
30683068

30693069
final override def signature(implicit ctx: Context): Signature = {
30703070
if (ctx.runId != mySignatureRunId) {
@@ -3357,7 +3357,7 @@ object Types {
33573357
companion.eq(ContextualMethodType) ||
33583358
companion.eq(ErasedContextualMethodType)
33593359

3360-
def computeSignature(implicit ctx: Context): Signature = {
3360+
protected[dotc] def computeSignature(implicit ctx: Context): Signature = {
33613361
val params = if (isErasedMethod) Nil else paramInfos
33623362
resultSignature.prependTermParams(params, isJavaMethod)
33633363
}
@@ -3592,7 +3592,7 @@ object Types {
35923592
assert(resType.isInstanceOf[TermType], this)
35933593
assert(paramNames.nonEmpty)
35943594

3595-
def computeSignature(implicit ctx: Context): Signature =
3595+
protected[dotc] def computeSignature(implicit ctx: Context): Signature =
35963596
resultSignature.prependTypeParams(paramNames.length)
35973597

35983598
override def isContextualMethod = resType.isContextualMethod

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,20 @@ class TreeChecker extends Phase with SymTransformer {
9292
if (ctx.phaseId <= ctx.erasurePhase.id) {
9393
val cur = symd.info
9494
val initial = symd.initial.info
95-
assert(cur.signature == initial.signature,
96-
i"""Signature of $symd changed at phase ${ctx.phase}
95+
val curSig = cur match {
96+
case cur: SignatureCachingType =>
97+
// Bypass the signature cache, it might hide a signature change
98+
cur.computeSignature
99+
case _ =>
100+
cur.signature
101+
}
102+
assert(curSig == initial.signature,
103+
i"""Signature of ${sym.showLocated} changed at phase ${ctx.base.squashed(ctx.phase.prev)}
97104
|Initial info: ${initial}
98105
|Initial sig : ${initial.signature}
99106
|Current info: ${cur}
100-
|Current sig : ${cur.signature}""")
107+
|Current sig : ${curSig}
108+
|Current cached sig: ${cur.signature}""")
101109
}
102110

103111
symd

tests/pos/local-signature.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class A {
2+
def bn(x: => Any): Any = x
3+
def foo: Unit = {
4+
bn({
5+
class A
6+
def foo(x: A): Unit = {}
7+
foo(new A)
8+
})
9+
}
10+
}

0 commit comments

Comments
 (0)