Skip to content

Commit 4543d58

Browse files
committed
Add MethodOrPoly#isSignature(isJava) overload
This makes it possible to compute the Java or Scala signature of a method, regardless of whether it was defined as a JavaMethod or not. Because there's nothing left that is shareable, this required removing SignatureCachingType and duplicating the signature caching logic between MethodOrPoly and NamedType. This commit itself does not change any semantics, but this new method will be useful for the next commit.
1 parent 3c837f9 commit 4543d58

File tree

2 files changed

+82
-66
lines changed

2 files changed

+82
-66
lines changed

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

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ object Types {
19991999

20002000
// --- NamedTypes ------------------------------------------------------------------
20012001

2002-
abstract class NamedType extends CachedProxyType with ValueType with SignatureCachingType { self =>
2002+
abstract class NamedType extends CachedProxyType with ValueType { self =>
20032003

20042004
type ThisType >: this.type <: NamedType
20052005
type ThisName <: Name
@@ -2015,11 +2015,13 @@ object Types {
20152015
private var lastSymbol: Symbol = null
20162016
private var checkedPeriod: Period = Nowhere
20172017
private var myStableHash: Byte = 0
2018+
private var mySignature: Signature = _
2019+
private var mySignatureRunId: Int = NoRunId
20182020

20192021
// Invariants:
2020-
// (1) checkedPeriod != Nowhere => lastDenotation != null
2021-
// (2) lastDenotation != null => lastSymbol != null
2022-
// (3) mySigRunId != NoRunId => mySig != null
2022+
// (1) checkedPeriod != Nowhere => lastDenotation != null
2023+
// (2) lastDenotation != null => lastSymbol != null
2024+
// (3) mySignatureRunId != NoRunId => mySignature != null
20232025

20242026
def isType: Boolean = isInstanceOf[TypeRef]
20252027
def isTerm: Boolean = isInstanceOf[TermRef]
@@ -2037,15 +2039,22 @@ object Types {
20372039
case sym: Symbol => sym.originDenotation.name
20382040
}
20392041

2040-
/** The signature computed from the last known denotation with `sigFromDenot`,
2041-
* or if there is none, the signature of the symbol. Signatures are always
2042-
* computed before erasure, since some symbols change their signature at erasure.
2043-
*/
2044-
protected[dotc] def computeSignature(using Context): Signature =
2045-
val lastd = lastDenotation
2046-
if lastd != null then sigFromDenot(lastd)
2047-
else if ctx.erasedTypes then atPhase(erasurePhase)(computeSignature)
2048-
else symbol.asSeenFrom(prefix).signature
2042+
final override def signature(using Context): Signature =
2043+
/** The signature computed from the last known denotation with `sigFromDenot`,
2044+
* or if there is none, the signature of the symbol. Signatures are always
2045+
* computed before erasure, since some symbols change their signature at erasure.
2046+
*/
2047+
def computeSignature(using Context): Signature =
2048+
val lastd = lastDenotation
2049+
if lastd != null then sigFromDenot(lastd)
2050+
else if ctx.erasedTypes then atPhase(erasurePhase)(computeSignature)
2051+
else symbol.asSeenFrom(prefix).signature
2052+
2053+
if ctx.runId != mySignatureRunId then
2054+
mySignature = computeSignature
2055+
if !mySignature.isUnderDefined then mySignatureRunId = ctx.runId
2056+
mySignature
2057+
end signature
20492058

20502059
/** The signature computed from the current denotation with `sigFromDenot` if it is
20512060
* known without forcing.
@@ -3219,39 +3228,11 @@ object Types {
32193228
// is that most poly types are cyclic via poly params,
32203229
// and therefore two different poly types would never be equal.
32213230

3222-
/** A trait that mixes in functionality for signature caching */
3223-
trait SignatureCachingType extends TermType {
3224-
protected var mySignature: Signature = _
3225-
protected var mySignatureRunId: Int = NoRunId
3226-
3227-
protected[dotc] def computeSignature(using Context): Signature
3228-
3229-
final override def signature(using Context): Signature = {
3230-
if (ctx.runId != mySignatureRunId) {
3231-
mySignature = computeSignature
3232-
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
3233-
}
3234-
mySignature
3235-
}
3236-
}
3237-
3238-
trait MethodicType extends TermType {
3239-
protected def resultSignature(using Context): Signature = try resultType match {
3240-
case rtp: MethodicType => rtp.signature
3241-
case tp =>
3242-
if (tp.isRef(defn.UnitClass)) Signature(Nil, defn.UnitClass.fullName.asTypeName)
3243-
else Signature(tp, isJava = false)
3244-
}
3245-
catch {
3246-
case ex: AssertionError =>
3247-
println(i"failure while taking result signature of $this: $resultType")
3248-
throw ex
3249-
}
3250-
}
3231+
trait MethodicType extends TermType
32513232

32523233
/** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */
32533234
abstract case class ExprType(resType: Type)
3254-
extends CachedProxyType with TermType with MethodicType {
3235+
extends CachedProxyType with MethodicType {
32553236
override def resultType(using Context): Type = resType
32563237
override def underlying(using Context): Type = resType
32573238

@@ -3371,7 +3352,58 @@ object Types {
33713352
final override def equals(that: Any): Boolean = equals(that, null)
33723353
}
33733354

3374-
abstract class MethodOrPoly extends UncachedGroundType with LambdaType with MethodicType with SignatureCachingType {
3355+
/** The superclass of MethodType and PolyType. */
3356+
sealed abstract class MethodOrPoly extends UncachedGroundType with LambdaType with MethodicType {
3357+
3358+
// Invariants:
3359+
// (1) mySignatureRunId != NoRunId => mySignature != null
3360+
// (2) myJavaSignatureRunId != NoRunId => myJavaSignature != null
3361+
3362+
private var mySignature: Signature = _
3363+
private var mySignatureRunId: Int = NoRunId
3364+
private var myJavaSignature: Signature = _
3365+
private var myJavaSignatureRunId: Int = NoRunId
3366+
3367+
/** If `isJava` is false, the Scala signature of this method.
3368+
* Otherwise, the signature of this method assuming it is part
3369+
* of a Java class. This distinction is needed because
3370+
* the same method type might be part of both a Java and Scala
3371+
* class and each language has different type erasure rules.
3372+
*/
3373+
def signature(isJava: Boolean)(using Context): Signature =
3374+
def computeSignature(isJava: Boolean)(using Context): Signature =
3375+
val resultSignature = resultType match
3376+
case tp: MethodOrPoly => tp.signature(isJava)
3377+
case tp: ExprType => tp.signature
3378+
case tp =>
3379+
if tp.isRef(defn.UnitClass) then Signature(Nil, defn.UnitClass.fullName.asTypeName)
3380+
else Signature(tp, isJava = false)
3381+
this match
3382+
case tp: MethodType =>
3383+
val params = if (isErasedMethod) Nil else tp.paramInfos
3384+
resultSignature.prependTermParams(params, isJava)
3385+
case tp: PolyType =>
3386+
resultSignature.prependTypeParams(tp.paramNames.length)
3387+
3388+
if isJava then
3389+
if ctx.runId != myJavaSignatureRunId then
3390+
myJavaSignature = computeSignature(isJava)
3391+
if !myJavaSignature.isUnderDefined then myJavaSignatureRunId = ctx.runId
3392+
myJavaSignature
3393+
else
3394+
if ctx.runId != mySignatureRunId then
3395+
mySignature = computeSignature(isJava)
3396+
if !mySignature.isUnderDefined then mySignatureRunId = ctx.runId
3397+
mySignature
3398+
end signature
3399+
3400+
final override def signature(using Context): Signature =
3401+
def isJava(tp: Type): Boolean = tp match
3402+
case tp: PolyType => isJava(tp.resultType)
3403+
case tp: MethodType => tp.isJavaMethod
3404+
case _ => false
3405+
signature(isJava = isJava(this))
3406+
33753407
final override def hashCode: Int = System.identityHashCode(this)
33763408

33773409
final override def equals(that: Any): Boolean = equals(that, null)
@@ -3531,11 +3563,6 @@ object Types {
35313563
companion.eq(ContextualMethodType) ||
35323564
companion.eq(ErasedContextualMethodType)
35333565

3534-
protected[dotc] def computeSignature(using Context): Signature = {
3535-
val params = if (isErasedMethod) Nil else paramInfos
3536-
resultSignature.prependTermParams(params, isJavaMethod)
3537-
}
3538-
35393566
protected def prefixString: String = companion.prefixString
35403567
}
35413568

@@ -3766,9 +3793,6 @@ object Types {
37663793
assert(resType.isInstanceOf[TermType], this)
37673794
assert(paramNames.nonEmpty)
37683795

3769-
protected[dotc] def computeSignature(using Context): Signature =
3770-
resultSignature.prependTypeParams(paramNames.length)
3771-
37723796
override def isContextualMethod = resType.isContextualMethod
37733797
override def isImplicitMethod = resType.isImplicitMethod
37743798

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

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,14 @@ class TreeChecker extends Phase with SymTransformer {
9090
// Signatures are used to disambiguate overloads and need to stay stable
9191
// until erasure, see the comment above `Compiler#phases`.
9292
if (ctx.phaseId <= erasurePhase.id) {
93-
val cur = symd.info
94-
val initial = symd.initial.info
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,
93+
val initial = symd.initial
94+
assert(symd.signature == initial.signature,
10395
i"""Signature of ${sym.showLocated} changed at phase ${ctx.base.fusedContaining(ctx.phase.prev)}
104-
|Initial info: ${initial}
96+
|Initial info: ${initial.info}
97+
|Init pre: ${initial.prefix.toString}
10598
|Initial sig : ${initial.signature}
106-
|Current info: ${cur}
107-
|Current sig : ${curSig}
108-
|Current cached sig: ${cur.signature}""")
99+
|Current info: ${symd.info}
100+
|Current sig : ${symd.signature}""")
109101
}
110102

111103
symd

0 commit comments

Comments
 (0)