From 9753483b028a6b6536fcc3aba91771ec0d1c88d3 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 28 May 2018 16:13:14 +0200 Subject: [PATCH 1/3] Fix signature caching in NamedType Underdefined signatures cannot be cached, this matches the logic in MethodicType. I haven't managed to create a testcase that fails without this, but it should be the Right Thing to do anyway. --- compiler/src/dotty/tools/dotc/core/Types.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 79e4a469b00a..4f630b83ac41 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1593,6 +1593,7 @@ object Types { private[this] var myName: Name = null private[this] var mySig: Signature = null + private[this] var mySigRunId: Int = NoRunId private[this] var lastDenotation: Denotation = null private[this] var lastSymbol: Symbol = null private[this] var checkedPeriod: Period = Nowhere @@ -1601,6 +1602,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] @@ -1622,7 +1624,10 @@ object Types { * signature of the symbol */ final override def signature(implicit ctx: Context): Signature = { - if (mySig == null) mySig = computeSignature + if (ctx.runId != mySigRunId) { + mySig = computeSignature + if (!mySig.isUnderDefined) mySigRunId = ctx.runId + } mySig } @@ -1637,7 +1642,7 @@ object Types { * Otherwise NotAMethod. */ private def currentSignature(implicit ctx: Context): Signature = - if (mySig != null) mySig + if (ctx.runId == mySigRunId) mySig else { val lastd = lastDenotation if (lastd != null) lastd.signature From bf913475cdf5affa6e6585b22dc75733665320e4 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 28 May 2018 16:23:30 +0200 Subject: [PATCH 2/3] Refactor signature caching Avoid duplication between MethodicType and NamedType --- .../src/dotty/tools/dotc/core/Types.scala | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 4f630b83ac41..56c46804636b 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -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 @@ -1592,8 +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 mySigRunId: Int = NoRunId private[this] var lastDenotation: Denotation = null private[this] var lastSymbol: Symbol = null private[this] var checkedPeriod: Period = Nowhere @@ -1623,15 +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 (ctx.runId != mySigRunId) { - mySig = computeSignature - if (!mySig.isUnderDefined) mySigRunId = ctx.runId - } - 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 @@ -1642,7 +1632,7 @@ object Types { * Otherwise NotAMethod. */ private def currentSignature(implicit ctx: Context): Signature = - if (ctx.runId == mySigRunId) mySig + if (ctx.runId == mySignatureRunId) mySignature else { val lastd = lastDenotation if (lastd != null) lastd.signature @@ -2589,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 => @@ -2607,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. */ From 3652d94699cff2f99a88b00344beac2521357708 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 28 May 2018 16:27:48 +0200 Subject: [PATCH 3/3] Signature: Fix documentation `fixSignature` no longer exists. Instead, we expect the users of signatures to not cache underdefined signatures. --- compiler/src/dotty/tools/dotc/core/Signature.scala | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index b1bc760df57e..b9856dcb8e4f 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -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 @@ -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))