Skip to content

Commit d3ba65d

Browse files
committed
Merge pull request #921 from dotty-staging/polytypes-hashcodes
Add stable hash codes to PolyTypes and PolyParams.
2 parents 7cfd3ca + fc5e2cf commit d3ba65d

File tree

2 files changed

+30
-9
lines changed

2 files changed

+30
-9
lines changed

src/dotty/tools/dotc/core/Hashable.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,24 @@ trait Hashable {
3030

3131
protected def hashSeed: Int = getClass.hashCode
3232

33-
private def finishHash(hashCode: Int, arity: Int): Int =
33+
protected final def finishHash(hashCode: Int, arity: Int): Int =
3434
avoidNotCached(hashing.finalizeHash(hashCode, arity))
3535

3636
final def identityHash = avoidNotCached(System.identityHashCode(this))
3737

38-
private def finishHash(seed: Int, arity: Int, tp: Type): Int = {
38+
protected def finishHash(seed: Int, arity: Int, tp: Type): Int = {
3939
val elemHash = tp.hash
4040
if (elemHash == NotCached) return NotCached
4141
finishHash(hashing.mix(seed, elemHash), arity + 1)
4242
}
4343

44-
private def finishHash(seed: Int, arity: Int, tp1: Type, tp2: Type): Int = {
44+
protected def finishHash(seed: Int, arity: Int, tp1: Type, tp2: Type): Int = {
4545
val elemHash = tp1.hash
4646
if (elemHash == NotCached) return NotCached
4747
finishHash(hashing.mix(seed, elemHash), arity + 1, tp2)
4848
}
4949

50-
private def finishHash(seed: Int, arity: Int, tps: List[Type]): Int = {
50+
protected def finishHash(seed: Int, arity: Int, tps: List[Type]): Int = {
5151
var h = seed
5252
var xs = tps
5353
var len = arity
@@ -61,7 +61,7 @@ trait Hashable {
6161
finishHash(h, len)
6262
}
6363

64-
private def finishHash(seed: Int, arity: Int, tp: Type, tps: List[Type]): Int = {
64+
protected def finishHash(seed: Int, arity: Int, tp: Type, tps: List[Type]): Int = {
6565
val elemHash = tp.hash
6666
if (elemHash == NotCached) return NotCached
6767
finishHash(hashing.mix(seed, elemHash), arity + 1, tps)
@@ -88,6 +88,10 @@ trait Hashable {
8888
protected final def doHash(x1: Any, tp2: Type, tps3: List[Type]): Int =
8989
finishHash(hashing.mix(hashSeed, x1.hashCode), 1, tp2, tps3)
9090

91+
92+
protected final def doHash(x1: Int, x2: Int): Int =
93+
finishHash(hashing.mix(hashing.mix(hashSeed, x1), x2), 1)
94+
9195
protected final def addDelta(hc: Int, delta: Int) = avoidNotCached(hc + delta)
9296

9397
private def avoidNotCached(h: Int) = if (h == NotCached) NotCachedAlt else h

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import annotation.tailrec
3333
import Flags.FlagSet
3434
import typer.Mode
3535
import language.implicitConversions
36+
import scala.util.hashing.{ MurmurHash3 => hashing }
3637

3738
object Types {
3839

@@ -2253,12 +2254,14 @@ object Types {
22532254
}
22542255
}
22552256

2256-
case class PolyType(paramNames: List[TypeName])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)
2257+
abstract case class PolyType(paramNames: List[TypeName])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)
22572258
extends CachedGroundType with BindingType with TermType with MethodOrPoly {
22582259

22592260
val paramBounds = paramBoundsExp(this)
22602261
val resType = resultTypeExp(this)
22612262

2263+
assert(resType ne null)
2264+
22622265
override def resultType(implicit ctx: Context) = resType
22632266

22642267
protected def computeSignature(implicit ctx: Context) = resultSignature
@@ -2280,13 +2283,26 @@ object Types {
22802283

22812284
// need to override hashCode and equals to be object identity
22822285
// because paramNames by itself is not discriminatory enough
2283-
override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
2284-
override def computeHash = identityHash
2286+
override def equals(other: Any) = other match {
2287+
case other: PolyType =>
2288+
other.paramNames == this.paramNames && other.paramBounds == this.paramBounds && other.resType == this.resType
2289+
case _ => false
2290+
}
2291+
override def computeHash = {
2292+
doHash(paramNames, resType, paramBounds)
2293+
}
22852294

22862295
override def toString = s"PolyType($paramNames, $paramBounds, $resType)"
22872296
}
22882297

2298+
class CachedPolyType(paramNames: List[TypeName])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)
2299+
extends PolyType(paramNames)(paramBoundsExp, resultTypeExp)
2300+
22892301
object PolyType {
2302+
def apply(paramNames: List[TypeName])(paramBoundsExp: PolyType => List[TypeBounds], resultTypeExp: PolyType => Type)(implicit ctx: Context): PolyType = {
2303+
unique(new CachedPolyType(paramNames)(paramBoundsExp, resultTypeExp))
2304+
}
2305+
22902306
def fromSymbols(tparams: List[Symbol], resultType: Type)(implicit ctx: Context) =
22912307
if (tparams.isEmpty) resultType
22922308
else {
@@ -2362,7 +2378,8 @@ object Types {
23622378
// no customized hashCode/equals needed because cycle is broken in PolyType
23632379
override def toString = s"PolyParam(${binder.paramNames(paramNum)})"
23642380

2365-
override def computeHash = doHash(paramNum, binder)
2381+
override def computeHash = doHash(paramNum, binder.identityHash)
2382+
23662383
override def equals(that: Any) = that match {
23672384
case that: PolyParam =>
23682385
(this.binder eq that.binder) && this.paramNum == that.paramNum

0 commit comments

Comments
 (0)