Skip to content

Commit f9d7985

Browse files
committed
Structural equality for dependent types
`equals` of two isomorphic types should return true, even if they are dependencies to BindingTypes.
1 parent 3512530 commit f9d7985

File tree

2 files changed

+151
-48
lines changed

2 files changed

+151
-48
lines changed

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

Lines changed: 136 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,16 +1398,23 @@ object Types {
13981398
*/
13991399
def simplified(implicit ctx: Context) = ctx.simplify(this, null)
14001400

1401-
/** customized hash code of this type.
1402-
* NotCached for uncached types. Cached types
1403-
* compute hash and use it as the type's hashCode.
1401+
final override def equals(that: Any) = StructEquality.equals(this, that)
1402+
1403+
/** Is `this` isomorphic to that, using comparer `e`?
1404+
* It is assumed that `this ne that`.
14041405
*/
1405-
def hash: Int
1406+
def iso(that: Any, e: StructEquality): Boolean = false
14061407

14071408
/** Equality used for hash-consing; uses `eq` on all recursive invocations.
14081409
*/
14091410
def eql(that: Type): Boolean = this.equals(that)
14101411

1412+
/** customized hash code of this type.
1413+
* NotCached for uncached types. Cached types
1414+
* compute hash and use it as the type's hashCode.
1415+
*/
1416+
def hash: Int
1417+
14111418
/** Compute `hash` using given `Hashing` */
14121419
def computeHash(h: Hashing): Int
14131420

@@ -2015,10 +2022,10 @@ object Types {
20152022
}
20162023
}
20172024

2018-
override def equals(that: Any) = that match {
2025+
override def iso(that: Any, e: StructEquality): Boolean = that match {
20192026
case that: NamedType =>
20202027
this.designator == that.designator &&
2021-
this.prefix == that.prefix
2028+
e.equals(this.prefix, that.prefix)
20222029
case _ =>
20232030
false
20242031
}
@@ -2153,6 +2160,11 @@ object Types {
21532160
case that: ThisType => tref.eq(that.tref)
21542161
case _ => false
21552162
}
2163+
2164+
override def iso(that: Any, e: StructEquality): Boolean = that match {
2165+
case that: ThisType => e.equals(tref, that.tref)
2166+
case _ => false
2167+
}
21562168
}
21572169

21582170
final class CachedThisType(tref: TypeRef) extends ThisType(tref)
@@ -2181,6 +2193,12 @@ object Types {
21812193
case that: SuperType => thistpe.eq(that.thistpe) && supertpe.eq(that.supertpe)
21822194
case _ => false
21832195
}
2196+
2197+
override def iso(that: Any, e: StructEquality): Boolean = that match {
2198+
case that: SuperType =>
2199+
e.equals(thistpe, that.thistpe) && e.equals(supertpe, that.supertpe)
2200+
case _ => false
2201+
}
21842202
}
21852203

21862204
final class CachedSuperType(thistpe: Type, supertpe: Type) extends SuperType(thistpe, supertpe)
@@ -2197,6 +2215,11 @@ object Types {
21972215
override def underlying(implicit ctx: Context) = value.tpe
21982216

21992217
override def computeHash(h: Hashing) = h.doHash(getClass, value)
2218+
2219+
override def iso(that: Any, e: StructEquality): Boolean = that match {
2220+
case that: ConstantType => value.equals(that.value)
2221+
case _ => false
2222+
}
22002223
}
22012224

22022225
final class CachedConstantType(value: Constant) extends ConstantType(value)
@@ -2223,7 +2246,6 @@ object Types {
22232246
def evaluating = computed && myRef == null
22242247
override def underlying(implicit ctx: Context) = ref
22252248
override def toString = s"LazyRef(${if (computed) myRef else "..."})"
2226-
override def equals(other: Any) = this.eq(other.asInstanceOf[AnyRef])
22272249
override def hashCode = System.identityHashCode(this)
22282250
}
22292251

@@ -2269,6 +2291,14 @@ object Types {
22692291
parent.eq(that.parent)
22702292
case _ => false
22712293
}
2294+
2295+
override def iso(that: Any, e: StructEquality): Boolean = that match {
2296+
case that: RefinedType =>
2297+
refinedName.eq(that.refinedName) &&
2298+
e.equals(refinedInfo, that.refinedInfo) &&
2299+
e.equals(parent, that.parent)
2300+
case _ => false
2301+
}
22722302
}
22732303

22742304
class CachedRefinedType(parent: Type, refinedName: Name, refinedInfo: Type)
@@ -2324,15 +2354,16 @@ object Types {
23242354
refacc.apply(false, tp)
23252355
}
23262356

2327-
override def computeHash(h: Hashing) = h.doHash(getClass, parent)
2357+
override def computeHash(h: Hashing) = h.withBinder(this).doHash(getClass, parent)
23282358

2329-
override def equals(that: Any) = that match {
2330-
case that: RecType => parent == that.parent
2359+
override def eql(that: Type) = that match {
2360+
case that: RecType => parent.eq(that.parent)
23312361
case _ => false
23322362
}
23332363

2334-
override def eql(that: Type) = that match {
2335-
case that: RecType => parent.eq(that.parent)
2364+
override def iso(that: Any, e: StructEquality) = that match {
2365+
case that: RecType =>
2366+
e.withBinders(this, that).equals(parent, that.parent)
23362367
case _ => false
23372368
}
23382369

@@ -2436,6 +2467,11 @@ object Types {
24362467
case that: AndType => tp1.eq(that.tp1) && tp2.eq(that.tp2)
24372468
case _ => false
24382469
}
2470+
2471+
override def iso(that: Any, e: StructEquality) = that match {
2472+
case that: AndType => e.equals(tp1, that.tp1) && e.equals(tp2, that.tp2)
2473+
case _ => false
2474+
}
24392475
}
24402476

24412477
final class CachedAndType(tp1: Type, tp2: Type) extends AndType(tp1, tp2)
@@ -2497,6 +2533,11 @@ object Types {
24972533
case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2)
24982534
case _ => false
24992535
}
2536+
2537+
override def iso(that: Any, e: StructEquality) = that match {
2538+
case that: OrType => e.equals(tp1, that.tp1) && e.equals(tp2, that.tp2)
2539+
case _ => false
2540+
}
25002541
}
25012542

25022543
final class CachedOrType(tp1: Type, tp2: Type) extends OrType(tp1, tp2)
@@ -2563,6 +2604,11 @@ object Types {
25632604
case that: ExprType => resType.eq(that.resType)
25642605
case _ => false
25652606
}
2607+
2608+
override def iso(that: Any, e: StructEquality) = that match {
2609+
case that: ExprType => e.equals(resType, that.resType)
2610+
case _ => false
2611+
}
25662612
}
25672613

25682614
final class CachedExprType(resultType: Type) extends ExprType(resultType)
@@ -2641,30 +2687,33 @@ object Types {
26412687
abstract class HKLambda extends CachedProxyType with LambdaType {
26422688
final override def underlying(implicit ctx: Context) = resType
26432689

2644-
final override def computeHash(h: Hashing) = h.doHash(getClass, paramNames, resType, paramInfos)
2690+
final override def computeHash(h: Hashing) =
2691+
h.withBinder(this).doHash(getClass, paramNames, resType, paramInfos)
26452692

2646-
final override def equals(that: Any) = that match {
2693+
final override def eql(that: Type) = that match {
26472694
case that: HKLambda =>
2648-
paramNames == that.paramNames &&
2649-
paramInfos == that.paramInfos &&
2650-
resType == that.resType &&
2695+
paramNames.equals(that.paramNames) &&
2696+
paramInfos.equals(that.paramInfos) &&
2697+
resType.equals(that.resType) &&
26512698
companion.eq(that.companion)
26522699
case _ =>
26532700
false
26542701
}
26552702

2656-
final override def eql(that: Type) = that match {
2703+
final override def iso(that: Any, e: StructEquality) = that match {
26572704
case that: HKLambda =>
2658-
paramNames.equals(that.paramNames) &&
2659-
paramInfos.equals(that.paramInfos) &&
2660-
resType.equals(that.resType) &&
2661-
companion.eq(that.companion)
2705+
paramNames.eqElements(that.paramNames) &&
2706+
companion.eq(that.companion) && {
2707+
val e1 = e.withBinders(this, that)
2708+
e1.equals(paramInfos, that.paramInfos) &&
2709+
e1.equals(resType, that.resType)
2710+
}
26622711
case _ =>
26632712
false
26642713
}
26652714
}
26662715

2667-
trait MethodOrPoly extends LambdaType with MethodicType
2716+
trait MethodOrPoly extends LambdaType with MethodicType // TODO: Make PolyTypes cached
26682717

26692718
trait TermLambda extends LambdaType { thisLambdaType =>
26702719
import DepStatus._
@@ -2800,23 +2849,25 @@ object Types {
28002849

28012850
final override def computeHash(h: Hashing) = h.doHash(getClass, paramNames, resType, paramInfos)
28022851

2803-
final override def equals(that: Any) = that match {
2852+
final override def eql(that: Type) = that match {
28042853
case that: MethodType =>
2805-
paramNames == that.paramNames &&
2806-
paramInfos == that.paramInfos &&
2807-
resType == that.resType &&
2854+
paramNames.eqElements(that.paramNames) &&
2855+
paramInfos.eqElements(that.paramInfos) &&
2856+
resType.eq(that.resType) &&
28082857
companion.eq(that.companion)
28092858
case _ =>
28102859
false
28112860
}
28122861

2813-
final override def eql(that: Type) = that match {
2862+
final override def iso(that: Any, e: StructEquality) = that match {
28142863
case that: MethodType =>
28152864
paramNames.eqElements(that.paramNames) &&
2816-
paramInfos.eqElements(that.paramInfos) &&
2817-
resType.eq(that.resType) &&
2818-
companion.eq(that.companion)
2819-
case _ =>
2865+
companion.eq(that.companion) && {
2866+
val e1 = e.withBinders(this, that)
2867+
e1.equals(paramInfos, that.paramInfos) &&
2868+
e1.equals(resType, that.resType)
2869+
}
2870+
case _ =>
28202871
false
28212872
}
28222873

@@ -3008,6 +3059,18 @@ object Types {
30083059
case _ => this
30093060
}
30103061

3062+
final override def iso(that: Any, e: StructEquality) = that match { // TODO: Move up to MethodOrPoly
3063+
case that: PolyType =>
3064+
paramNames.eqElements(that.paramNames) &&
3065+
companion.eq(that.companion) && {
3066+
val e1 = e.withBinders(this, that)
3067+
e1.equals(paramInfos, that.paramInfos) &&
3068+
e1.equals(resType, that.resType)
3069+
}
3070+
case _ =>
3071+
false
3072+
}
3073+
30113074
protected def prefixString = "PolyType"
30123075
}
30133076

@@ -3136,12 +3199,18 @@ object Types {
31363199
def derivedAppliedType(tycon: Type, args: List[Type])(implicit ctx: Context): Type =
31373200
if ((tycon eq this.tycon) && (args eq this.args)) this
31383201
else tycon.appliedTo(args)
3202+
3203+
override def computeHash(h: Hashing) = h.doHash(getClass, tycon, args)
3204+
override def eql(that: Type) = this eq that // safe because applied types are hash-consed separately
3205+
3206+
final override def iso(that: Any, e: StructEquality) = that match {
3207+
case that: AppliedType => e.equals(tycon, that.tycon) && e.equals(args, that.args)
3208+
case _ => false
3209+
}
31393210
}
31403211

31413212
final class CachedAppliedType(tycon: Type, args: List[Type], hc: Int) extends AppliedType(tycon, args) {
31423213
myHash = hc
3143-
override def computeHash(h: Hashing) = h.doHash(getClass, tycon, args)
3144-
override def eql(that: Type) = this eq that // safe because applied types are hash-consed separately
31453214
}
31463215

31473216
object AppliedType {
@@ -3172,8 +3241,8 @@ object Types {
31723241

31733242
override def computeHash(h: Hashing) = h.doHash(getClass, paramNum, h.identityHash(binder))
31743243

3175-
override def equals(that: Any) = that match {
3176-
case that: ParamRef => binder.eq(that.binder) && paramNum == that.paramNum
3244+
override def iso(that: Any, e: StructEquality) = that match {
3245+
case that: ParamRef => e.equalBinders(binder, that.binder) && paramNum == that.paramNum
31773246
case _ => false
31783247
}
31793248

@@ -3229,8 +3298,8 @@ object Types {
32293298
// between RecTypes and RecRefs.
32303299
override def computeHash(h: Hashing) = h.addDelta(h.identityHash(binder), 41)
32313300

3232-
override def equals(that: Any) = that match {
3233-
case that: RecThis => binder.eq(that.binder)
3301+
override def iso(that: Any, e: StructEquality) = that match {
3302+
case that: RecThis => e.equalBinders(binder, that.binder)
32343303
case _ => false
32353304
}
32363305

@@ -3249,7 +3318,6 @@ object Types {
32493318
def derivedSkolemType(info: Type)(implicit ctx: Context) =
32503319
if (info eq this.info) this else SkolemType(info)
32513320
override def hashCode: Int = System.identityHashCode(this)
3252-
override def equals(that: Any) = this.eq(that.asInstanceOf[AnyRef])
32533321

32543322
def withName(name: Name): this.type = { myRepr = name; this }
32553323

@@ -3356,7 +3424,6 @@ object Types {
33563424
}
33573425

33583426
override def computeHash(h: Hashing): Int = h.identityHash(this)
3359-
override def equals(that: Any) = this.eq(that.asInstanceOf[AnyRef])
33603427

33613428
override def toString = {
33623429
def instStr = if (inst.exists) s" -> $inst" else ""
@@ -3442,6 +3509,16 @@ object Types {
34423509
case _ => false
34433510
}
34443511

3512+
override def iso(that: Any, e: StructEquality) = that match {
3513+
case that: ClassInfo =>
3514+
e.equals(prefix, that.prefix) &&
3515+
cls.eq(that.cls) &&
3516+
e.equals(classParents, that.classParents) &&
3517+
decls.eq(that.decls) &&
3518+
selfInfo.eq(that.selfInfo)
3519+
case _ => false
3520+
}
3521+
34453522
override def toString = s"ClassInfo($prefix, $cls, $classParents)"
34463523
}
34473524

@@ -3515,9 +3592,9 @@ object Types {
35153592

35163593
override def computeHash(h: Hashing) = h.doHash(getClass, lo, hi)
35173594

3518-
override def equals(that: Any): Boolean = that match {
3595+
override def iso(that: Any, e: StructEquality): Boolean = that match {
35193596
case that: TypeAlias => false
3520-
case that: TypeBounds => lo == that.lo && hi == that.hi
3597+
case that: TypeBounds => e.equals(lo, that.lo) && e.equals(hi, that.hi)
35213598
case _ => false
35223599
}
35233600

@@ -3538,8 +3615,8 @@ object Types {
35383615

35393616
override def computeHash(h: Hashing) = h.doHash(getClass, alias)
35403617

3541-
override def equals(that: Any): Boolean = that match {
3542-
case that: TypeAlias => alias == that.alias
3618+
override def iso(that: Any, e: StructEquality): Boolean = that match {
3619+
case that: TypeAlias => e.equals(alias, that.alias)
35433620
case _ => false
35443621
}
35453622

@@ -3581,6 +3658,11 @@ object Types {
35813658
derivedAnnotatedType(tpe.stripTypeVar, annot)
35823659

35833660
override def stripAnnots(implicit ctx: Context): Type = tpe.stripAnnots
3661+
3662+
override def iso(that: Any, e: StructEquality): Boolean = that match {
3663+
case that: AnnotatedType => e.equals(tpe, that.tpe) && (annot `eq` that.annot)
3664+
case _ => false
3665+
}
35843666
}
35853667

35863668
object AnnotatedType {
@@ -3601,6 +3683,11 @@ object Types {
36013683
case that: JavaArrayType => elemType.eq(that.elemType)
36023684
case _ => false
36033685
}
3686+
3687+
override def iso(that: Any, e: StructEquality) = that match {
3688+
case that: JavaArrayType => e.equals(elemType, that.elemType)
3689+
case _ => false
3690+
}
36043691
}
36053692
final class CachedJavaArrayType(elemType: Type) extends JavaArrayType(elemType)
36063693
object JavaArrayType {
@@ -3664,6 +3751,11 @@ object Types {
36643751
case that: WildcardType => optBounds.eq(that.optBounds)
36653752
case _ => false
36663753
}
3754+
3755+
override def iso(that: Any, e: StructEquality) = that match {
3756+
case that: WildcardType => e.equals(optBounds, that.optBounds)
3757+
case _ => false
3758+
}
36673759
}
36683760

36693761
final class CachedWildcardType(optBounds: Type) extends WildcardType(optBounds)

0 commit comments

Comments
 (0)