Skip to content

Fix signature caching in NamedType #4593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions compiler/src/dotty/tools/dotc/core/Signature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,15 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) {

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

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

/** The signature of a method with no parameters and result type `resultType`. */
/** The signature of a method with no parameters and result type `resultType`.
*
* The resulting value is only cacheable if `isUnderDefined == false`,
* otherwise the signature will change once the contained type variables have
* been instantiated.
*/
def apply(resultType: Type, isJava: Boolean)(implicit ctx: Context): Signature = {
assert(!resultType.isInstanceOf[ExprType])
apply(Nil, sigName(resultType, isJava))
Expand Down
38 changes: 17 additions & 21 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1580,7 +1580,7 @@ object Types {

// --- NamedTypes ------------------------------------------------------------------

abstract class NamedType extends CachedProxyType with ValueType { self =>
abstract class NamedType extends CachedProxyType with ValueType with SignatureCachingType { self =>

type ThisType >: this.type <: NamedType
type ThisName <: Name
Expand All @@ -1592,7 +1592,6 @@ object Types {
assert(prefix.isValueType || (prefix eq NoPrefix), s"invalid prefix $prefix")

private[this] var myName: Name = null
private[this] var mySig: Signature = null
private[this] var lastDenotation: Denotation = null
private[this] var lastSymbol: Symbol = null
private[this] var checkedPeriod: Period = Nowhere
Expand All @@ -1601,6 +1600,7 @@ object Types {
// Invariants:
// (1) checkedPeriod != Nowhere => lastDenotation != null
// (2) lastDenotation != null => lastSymbol != null
// (3) mySigRunId != NoRunId => mySig != null

def isType = isInstanceOf[TypeRef]
def isTerm = isInstanceOf[TermRef]
Expand All @@ -1621,12 +1621,7 @@ object Types {
/** The signature of the last known denotation, or if there is none, the
* signature of the symbol
*/
final override def signature(implicit ctx: Context): Signature = {
if (mySig == null) mySig = computeSignature
mySig
}

def computeSignature(implicit ctx: Context): Signature = {
protected def computeSignature(implicit ctx: Context): Signature = {
val lastd = lastDenotation
if (lastd != null) lastd.signature
else symbol.asSeenFrom(prefix).signature
Expand All @@ -1637,7 +1632,7 @@ object Types {
* Otherwise NotAMethod.
*/
private def currentSignature(implicit ctx: Context): Signature =
if (mySig != null) mySig
if (ctx.runId == mySignatureRunId) mySignature
else {
val lastd = lastDenotation
if (lastd != null) lastd.signature
Expand Down Expand Up @@ -2584,13 +2579,22 @@ object Types {
// and therefore two different poly types would never be equal.

/** A trait that mixes in functionality for signature caching */
trait MethodicType extends TermType {

private[this] var mySignature: Signature = _
private[this] var mySignatureRunId: Int = NoRunId
trait SignatureCachingType extends TermType {
protected[this] var mySignature: Signature = _
protected[this] var mySignatureRunId: Int = NoRunId

protected def computeSignature(implicit ctx: Context): Signature

final override def signature(implicit ctx: Context): Signature = {
if (ctx.runId != mySignatureRunId) {
mySignature = computeSignature
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
}
mySignature
}
}

trait MethodicType extends SignatureCachingType {
protected def resultSignature(implicit ctx: Context) = try resultType match {
case rtp: MethodicType => rtp.signature
case tp =>
Expand All @@ -2602,14 +2606,6 @@ object Types {
println(i"failure while taking result signature of $this: $resultType")
throw ex
}

final override def signature(implicit ctx: Context): Signature = {
if (ctx.runId != mySignatureRunId) {
mySignature = computeSignature
if (!mySignature.isUnderDefined) mySignatureRunId = ctx.runId
}
mySignature
}
}

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