aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala107
1 files changed, 65 insertions, 42 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 32c36a563..e07410a89 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -23,25 +23,25 @@ class TypeComparer(initctx: Context) extends DotClass {
private var frozenConstraint = false
- private var myAnyType: Type = null
- private var myNothingType: Type = null
- private var myNullType: Type = null
- private var myObjectType: Type = null
- def AnyType = {
- if (myAnyType == null) myAnyType = defn.AnyType
- myAnyType
+ private var myAnyClass: ClassSymbol = null
+ private var myNothingClass: ClassSymbol = null
+ private var myNullClass: ClassSymbol = null
+ private var myObjectClass: ClassSymbol = null
+ def AnyClass = {
+ if (myAnyClass == null) myAnyClass = defn.AnyClass
+ myAnyClass
}
- def NothingType = {
- if (myNothingType == null) myNothingType = defn.NothingType
- myNothingType
+ def NothingClass = {
+ if (myNothingClass == null) myNothingClass = defn.NothingClass
+ myNothingClass
}
- def NullType = {
- if (myNullType == null) myNullType = defn.NullType
- myNullType
+ def NullClass = {
+ if (myNullClass == null) myNullClass = defn.NullClass
+ myNullClass
}
- def ObjectType = {
- if (myObjectType == null) myObjectType = defn.ObjectType
- myObjectType
+ def ObjectClass = {
+ if (myObjectClass == null) myObjectClass = defn.ObjectClass
+ myObjectClass
}
/** Add the constraint `<bounds.lo <: param <: bounds.hi>`
@@ -220,8 +220,8 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: RefinedType =>
isSubType(tp1, tp2.parent) && (
tp2.refinedName == nme.WILDCARD
- || (tp1 eq NothingType)
- || (tp1 eq NullType)
+ || (tp1.typeSymbol eq NothingClass)
+ || (tp1.typeSymbol eq NullClass)
|| tp1.member(tp2.refinedName).hasAltWith(alt =>
isSubType(alt.info, tp2.refinedInfo)))
case AndType(tp21, tp22) =>
@@ -258,29 +258,29 @@ class TypeComparer(initctx: Context) extends DotClass {
case TypeBounds(lo2, hi2) =>
tp1 match {
case TypeBounds(lo1, hi1) =>
- ((lo2 eq NothingType) || isSubType(lo2, lo1)) &&
- ((hi2 eq AnyType) || isSubType(hi1, hi2))
+ ((lo2.typeSymbol eq NothingClass) || isSubType(lo2, lo1)) &&
+ ((hi2.typeSymbol eq AnyClass) || isSubType(hi1, hi2))
case tp1: ClassInfo =>
val tt = tp1.typeConstructor // was typeTemplate
isSubType(lo2, tt) && isSubType(tt, hi2)
case _ =>
false
}
- /* needed?
- case ClassInfo(pre2, denot2) =>
- tp1 match {
- case ClassInfo(pre1, denot1) =>
- (denot1 eq denot2) && isSubType(pre2, pre1) // !!! or isSameType?
- }
-*/
+ case ClassInfo(pre2, cls2, _, _, _) =>
+ tp1 match {
+ case ClassInfo(pre1, cls1, _, _, _) =>
+ (cls1 eq cls2) && isSubType(pre2, pre1)
+ case _ =>
+ false
+ }
case _ =>
fourthTry(tp1, tp2)
}
def fourthTry(tp1: Type, tp2: Type): Boolean = tp1 match {
case tp1: TypeRef =>
- ((tp1 eq NothingType)
- || (tp1 eq NullType) && tp2.dealias.typeSymbol.isNonValueClass
+ ((tp1.symbol eq NothingClass)
+ || (tp1.symbol eq NullClass) && tp2.dealias.typeSymbol.isNonValueClass
|| (tp1.info match {
case TypeBounds(lo1, hi1) =>
isSubType(hi1, tp2) ||
@@ -386,8 +386,8 @@ class TypeComparer(initctx: Context) extends DotClass {
formals2 match {
case formal2 :: rest2 =>
(isSameType(formal1, formal2)
- || isJava1 && formal2 == ObjectType && formal1 == AnyType
- || isJava2 && formal1 == ObjectType && formal2 == AnyType) && matchingParams(rest1, rest2, isJava1, isJava2)
+ || isJava1 && formal2.typeSymbol == ObjectClass && formal1.typeSymbol == AnyClass
+ || isJava2 && formal1.typeSymbol == ObjectClass && formal2.typeSymbol == AnyClass) && matchingParams(rest1, rest2, isJava1, isJava2)
case nil =>
false
}
@@ -402,8 +402,8 @@ class TypeComparer(initctx: Context) extends DotClass {
def glb(tp1: Type, tp2: Type): Type =
if (tp1 eq tp2) tp1
- else if (!tp1.exists || (tp1 eq AnyType) || (tp2 eq NothingType)) tp2
- else if (!tp2.exists || (tp2 eq AnyType) || (tp1 eq NothingType)) tp1
+ else if (!tp1.exists || (tp1.typeSymbol eq AnyClass) || (tp2.typeSymbol eq NothingClass)) tp2
+ else if (!tp2.exists || (tp2.typeSymbol eq AnyClass) || (tp1.typeSymbol eq NothingClass)) tp1
else tp2 match { // normalize to disjunctive normal form if possible.
case OrType(tp21, tp22) =>
tp1 & tp21 | tp1 & tp22
@@ -424,11 +424,11 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: TypeBounds =>
return TypeBounds(tp1.lo | tp2.lo, tp1.hi & tp2.hi)
case tp2: ClassInfo =>
- throw new ClassMergeError(tp2, tp1)
+ return classMerge(tp2, tp1)
case _ =>
}
case tp1: ClassInfo =>
- throw new ClassMergeError(tp1, tp2)
+ return classMerge(tp1, tp2)
case _ =>
}
AndType(tp1, tp2)
@@ -438,12 +438,12 @@ class TypeComparer(initctx: Context) extends DotClass {
}
final def glb(tps: List[Type]): Type =
- (AnyType /: tps)(glb)
+ (defn.AnyType /: tps)(glb)
def lub(tp1: Type, tp2: Type): Type =
if (tp1 eq tp2) tp1
- else if (!tp1.exists || (tp1 eq AnyType) || (tp2 eq NothingType)) tp1
- else if (!tp2.exists || (tp2 eq AnyType) || (tp1 eq NothingType)) tp2
+ else if (!tp1.exists || (tp1.typeSymbol eq AnyClass) || (tp2.typeSymbol eq NothingClass)) tp1
+ else if (!tp2.exists || (tp2.typeSymbol eq AnyClass) || (tp1.typeSymbol eq NothingClass)) tp2
else {
val t1 = mergeIfSuper(tp1, tp2)
if (t1.exists) t1
@@ -457,11 +457,11 @@ class TypeComparer(initctx: Context) extends DotClass {
case tp2: TypeBounds =>
return TypeBounds(tp1.lo & tp2.lo, tp1.hi | tp2.hi)
case tp2: ClassInfo =>
- throw new ClassMergeError(tp2, tp1)
+ return classMerge(tp2, tp1)
case _ =>
}
case tp1: ClassInfo =>
- throw new ClassMergeError(tp1, tp2)
+ return classMerge(tp1, tp2)
case _ =>
}
OrType(tp1, tp2)
@@ -470,7 +470,7 @@ class TypeComparer(initctx: Context) extends DotClass {
}
final def lub(tps: List[Type]): Type =
- (NothingType /: tps)(lub)
+ (defn.NothingType /: tps)(lub)
/** Merge `t1` into `tp2` if t1 is a subtype of some &-summand of tp2.
*/
@@ -512,6 +512,29 @@ class TypeComparer(initctx: Context) extends DotClass {
NoType
}
+ /** Merge class info with other TypeType.
+ * The problem is how to generate a TypeType from the union or intersection
+ * of a ClassInfo and another TypeType. Generating an (empty) TypeBounds
+ * that refers to the class symbol via a TypeRef does not work; it leads to
+ * infinite loops when dereferencing proxies.
+ * The algorithm used instead is:
+ * 1. ClassInfos always override TypeBounds.
+ * 2. When merging two ClassInfos pick one of them. More precisely,
+ * pick the first, unless the second's prefix is a true subtype of the
+ * first's prefix or the second's owner is a true subclass of the first's owner.
+ * This is arbitrary, but I believe it is analogous to forming
+ * unfeasible TypeBounds (where lo is not a subtype of hi). Such TypeBounds
+ * can also be arbitrarily instantiated. In both cases we need to
+ * make sure that such types do not actually arise in source programs.
+ */
+ private def classMerge(cinfo: ClassInfo, tp2: Type)(implicit ctx: Context): Type = tp2 match {
+ case cinfo2: ClassInfo if isAsGood(cinfo2, cinfo) && !isAsGood(cinfo, cinfo2) => cinfo2
+ case _ => cinfo
+ }
+
+ private def isAsGood(cinfo1: ClassInfo, cinfo2: ClassInfo)(implicit ctx: Context): Boolean =
+ (cinfo1.prefix <:< cinfo2.prefix) || (cinfo1.cls.owner derivesFrom cinfo2.cls.owner)
+
def copyIn(ctx: Context) = new TypeComparer(ctx)
}
@@ -535,7 +558,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
}
override def isSubType(tp1: Type, tp2: Type) =
- traceIndented(s"${show(tp1)} <:< ${show(tp2)} ${tp1.getClass} ${defn.NothingType.getClass} ${tp1.normalizedPrefix} ${defn.NothingType.normalizedPrefix} ${tp1 eq defn.NothingType} ${tp1.typeSymbol eq defn.NothingClass}") {
+ traceIndented(s"${show(tp1)} <:< ${show(tp2)}") {
super.isSubType(tp1, tp2)
}