Skip to content

Commit ffc17d0

Browse files
authored
Merge pull request #4593 from dotty-staging/fix/signature-caching
Fix signature caching in NamedType
2 parents d0f1e60 + 3652d94 commit ffc17d0

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,15 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {
8787

8888
/** Construct a signature by prepending the signature names of the given `params`
8989
* to the parameter part of this signature.
90+
*
91+
* Like Signature#apply, the result is only cacheable if `isUnderDefined == false`.
9092
*/
9193
def prepend(params: List[Type], isJava: Boolean)(implicit ctx: Context) =
9294
Signature(params.map(p => sigName(p, isJava)) ++ paramsSig, resSig)
9395

9496
/** A signature is under-defined if its paramsSig part contains at least one
9597
* `tpnme.Uninstantiated`. Under-defined signatures arise when taking a signature
96-
* of a type that still contains uninstantiated type variables. They are eliminated
97-
* by `fixSignature` in `PostTyper`.
98+
* of a type that still contains uninstantiated type variables.
9899
*/
99100
def isUnderDefined(implicit ctx: Context) =
100101
paramsSig.contains(tpnme.Uninstantiated) || resSig == tpnme.Uninstantiated
@@ -116,7 +117,12 @@ object Signature {
116117
*/
117118
val OverloadedSignature = Signature(List(tpnme.OVERLOADED), EmptyTypeName)
118119

119-
/** The signature of a method with no parameters and result type `resultType`. */
120+
/** The signature of a method with no parameters and result type `resultType`.
121+
*
122+
* The resulting value is only cacheable if `isUnderDefined == false`,
123+
* otherwise the signature will change once the contained type variables have
124+
* been instantiated.
125+
*/
120126
def apply(resultType: Type, isJava: Boolean)(implicit ctx: Context): Signature = {
121127
assert(!resultType.isInstanceOf[ExprType])
122128
apply(Nil, sigName(resultType, isJava))

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

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,7 @@ object Types {
15811581

15821582
// --- NamedTypes ------------------------------------------------------------------
15831583

1584-
abstract class NamedType extends CachedProxyType with ValueType { self =>
1584+
abstract class NamedType extends CachedProxyType with ValueType with SignatureCachingType { self =>
15851585

15861586
type ThisType >: this.type <: NamedType
15871587
type ThisName <: Name
@@ -1593,7 +1593,6 @@ object Types {
15931593
assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix")
15941594

15951595
private[this] var myName: Name = null
1596-
private[this] var mySig: Signature = null
15971596
private[this] var lastDenotation: Denotation = null
15981597
private[this] var lastSymbol: Symbol = null
15991598
private[this] var checkedPeriod: Period = Nowhere
@@ -1602,6 +1601,7 @@ object Types {
16021601
// Invariants:
16031602
// (1) checkedPeriod != Nowhere => lastDenotation != null
16041603
// (2) lastDenotation != null => lastSymbol != null
1604+
// (3) mySigRunId != NoRunId => mySig != null
16051605

16061606
def isType = isInstanceOf[TypeRef]
16071607
def isTerm = isInstanceOf[TermRef]
@@ -1622,12 +1622,7 @@ object Types {
16221622
/** The signature of the last known denotation, or if there is none, the
16231623
* signature of the symbol
16241624
*/
1625-
final override def signature(implicit ctx: Context): Signature = {
1626-
if (mySig == null) mySig = computeSignature
1627-
mySig
1628-
}
1629-
1630-
def computeSignature(implicit ctx: Context): Signature = {
1625+
protected def computeSignature(implicit ctx: Context): Signature = {
16311626
val lastd = lastDenotation
16321627
if (lastd != null) lastd.signature
16331628
else symbol.asSeenFrom(prefix).signature
@@ -1638,7 +1633,7 @@ object Types {
16381633
* Otherwise NotAMethod.
16391634
*/
16401635
private def currentSignature(implicit ctx: Context): Signature =
1641-
if (mySig != null) mySig
1636+
if (ctx.runId == mySignatureRunId) mySignature
16421637
else {
16431638
val lastd = lastDenotation
16441639
if (lastd != null) lastd.signature
@@ -2585,13 +2580,22 @@ object Types {
25852580
// and therefore two different poly types would never be equal.
25862581

25872582
/** A trait that mixes in functionality for signature caching */
2588-
trait MethodicType extends TermType {
2589-
2590-
private[this] var mySignature: Signature = _
2591-
private[this] var mySignatureRunId: Int = NoRunId
2583+
trait SignatureCachingType extends TermType {
2584+
protected[this] var mySignature: Signature = _
2585+
protected[this] var mySignatureRunId: Int = NoRunId
25922586

25932587
protected def computeSignature(implicit ctx: Context): Signature
25942588

2589+
final override def signature(implicit ctx: Context): Signature = {
2590+
if (ctx.runId != mySignatureRunId) {
2591+
mySignature = computeSignature
2592+
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
2593+
}
2594+
mySignature
2595+
}
2596+
}
2597+
2598+
trait MethodicType extends SignatureCachingType {
25952599
protected def resultSignature(implicit ctx: Context) = try resultType match {
25962600
case rtp: MethodicType => rtp.signature
25972601
case tp =>
@@ -2603,14 +2607,6 @@ object Types {
26032607
println(i"failure while taking result signature of $this: $resultType")
26042608
throw ex
26052609
}
2606-
2607-
final override def signature(implicit ctx: Context): Signature = {
2608-
if (ctx.runId != mySignatureRunId) {
2609-
mySignature = computeSignature
2610-
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
2611-
}
2612-
mySignature
2613-
}
26142610
}
26152611

26162612
/** A by-name parameter type of the form `=> T`, or the type of a method with no parameter list. */

0 commit comments

Comments
 (0)