summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-11-08 18:12:25 +0000
committerPaul Phillips <paulp@improving.org>2010-11-08 18:12:25 +0000
commit8009f723b905509e9dfa22d8746787ebb0cd11a2 (patch)
tree6722a467f0384cfeb9dd459a5978976945dab5df
parent948f4228c1a279f49093dbc7dc042eea749c463d (diff)
downloadscala-8009f723b905509e9dfa22d8746787ebb0cd11a2.tar.gz
scala-8009f723b905509e9dfa22d8746787ebb0cd11a2.tar.bz2
scala-8009f723b905509e9dfa22d8746787ebb0cd11a2.zip
Modified the lub calculation in TypeKinds to av...
Modified the lub calculation in TypeKinds to avoid the icode checker failures described in ticket #3872. This does not alter the compiler's lub calculation as I'd hoped because I could not figure out how to accomplish this without having unintended consequences. I think that either Symbol.isLess could be adjusted, or perhaps the implementation of spanningTypes, or other places... but it eluded me and I defer to the type wizards. No review.
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala56
2 files changed, 42 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index f1be717d12..65b558b230 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -93,6 +93,7 @@ abstract class ICodes extends AnyRef
lazy val ObjectReference: TypeKind = REFERENCE(global.definitions.ObjectClass)
lazy val ThrowableReference: TypeKind = REFERENCE(global.definitions.ThrowableClass)
+ lazy val AnyRefReference: TypeKind = REFERENCE(global.definitions.AnyRefClass)
object icodeReader extends ICodeReader {
lazy val global: ICodes.this.global.type = ICodes.this.global
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
index 5e44d519cf..8909171587 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
@@ -54,14 +54,13 @@ trait TypeKinds { self: ICodes =>
sealed abstract class TypeKind {
def maxType(other: TypeKind): TypeKind
- def toType: Type = (reversePrimitiveMap get this) map (_.tpe) getOrElse {
+ def toType: Type = reversePrimitiveMap get this map (_.tpe) getOrElse {
this match {
case REFERENCE(cls) => cls.tpe
case ARRAY(elem) => arrayType(elem.toType)
case _ => abort("Unknown type kind.")
}
}
- def toTypeAt(ph: Phase): Type = atPhase(ph)(toType)
def isReferenceType = false
def isArrayType = false
@@ -71,8 +70,8 @@ trait TypeKinds { self: ICodes =>
final def isRefArrayOrBoxType = isRefOrArrayType || isBoxedType
final def isNothingType = this == REFERENCE(NothingClass)
final def isInterfaceType = this match {
- case REFERENCE(cls) if cls.isInterface => true
- case _ => false
+ case REFERENCE(cls) if cls.isInterface => true
+ case _ => false
}
final def isBoxOrInterfaceType = isBoxedType || isInterfaceType
@@ -131,11 +130,32 @@ trait TypeKinds { self: ICodes =>
* The lub is based on the lub of scala types.
*/
def lub(a: TypeKind, b: TypeKind): TypeKind = {
- /** The compiler will be altered so this returns the right thing for our
- * purposes here.
+ /** The compiler's lub calculation does not order classes before traits.
+ * This is apparently not wrong but it is inconvenient, and causes the
+ * icode checker to choke when things don't match up. My attempts to
+ * alter the calculation at the compiler level were failures, so in the
+ * interests of a working icode checker I'm making the adjustment here.
+ *
+ * Example where we'd like a different answer:
+ *
+ * abstract class Tom
+ * case object Bob extends Tom
+ * case object Harry extends Tom
+ * List(Bob, Harry) // compiler calculates "Product with Tom" rather than "Tom with Product"
+ *
+ * Here we make the adjustment by rewinding to a pre-erasure state and
+ * sifting through the parents for a class type.
*/
- def lub0(tk1: TypeKind, tk2: TypeKind): Type =
- global.lub(List(tk1.toType, tk2.toType))
+ def lub0(tk1: TypeKind, tk2: TypeKind): Type = atPhase(currentRun.uncurryPhase) {
+ import definitions._
+ val tp = global.lub(List(tk1.toType, tk2.toType))
+ val (front, rest) = tp.parents span (_.typeSymbol.hasTraitFlag)
+ if (front.isEmpty || rest.isEmpty) tp
+ else rest.head match {
+ case AnyClass | AnyRefClass | AnyValClass => tp
+ case x => x
+ }
+ }
// Approximate the JVM view of subtyping by collapsing boxed
// values and interfaces into AnyRef. If we try to be more precise
@@ -153,7 +173,7 @@ trait TypeKinds { self: ICodes =>
if (a == b) a
else if (a.isNothingType) b
else if (b.isNothingType) a
- else if (isBoxLub) REFERENCE(AnyRefClass)
+ else if (isBoxLub) AnyRefReference
else if (isIntLub) INT
else if (a.isRefOrArrayType && b.isRefOrArrayType) toTypeKind(lub0(a, b))
else throw new CheckerException("Incompatible types: " + a + " with " + b)
@@ -258,7 +278,7 @@ trait TypeKinds { self: ICodes =>
* use method 'lub'.
*/
override def maxType(other: TypeKind) = other match {
- case REFERENCE(_) | ARRAY(_) => REFERENCE(AnyRefClass)
+ case REFERENCE(_) | ARRAY(_) => AnyRefReference
case _ => uncomparable("REFERENCE", other)
}
@@ -295,7 +315,7 @@ trait TypeKinds { self: ICodes =>
*/
override def maxType(other: TypeKind) = other match {
case ARRAY(elem2) if elem == elem2 => ARRAY(elem)
- case ARRAY(_) | REFERENCE(_) => REFERENCE(AnyRefClass)
+ case ARRAY(_) | REFERENCE(_) => AnyRefReference
case _ => uncomparable("ARRAY", other)
}
@@ -317,7 +337,7 @@ trait TypeKinds { self: ICodes =>
* use method 'lub'.
*/
override def maxType(other: TypeKind) = other match {
- case REFERENCE(_) | ARRAY(_) | BOXED(_) => REFERENCE(AnyRefClass)
+ case REFERENCE(_) | ARRAY(_) | BOXED(_) => AnyRefReference
case _ => uncomparable("BOXED", other)
}
@@ -342,7 +362,7 @@ trait TypeKinds { self: ICodes =>
* use method 'lub'.
*/
override def maxType(other: TypeKind) = other match {
- case REFERENCE(_) => REFERENCE(AnyRefClass)
+ case REFERENCE(_) => AnyRefReference
case _ => uncomparable(other)
}
@@ -380,13 +400,19 @@ trait TypeKinds { self: ICodes =>
*/
private def arrayOrClassType(sym: Symbol, targs: List[Type]) = sym match {
case ArrayClass => ARRAY(toTypeKind(targs.head))
- case _ if sym.isClass => REFERENCE(sym)
+ case _ if sym.isClass => newReference(sym)
case _ =>
assert(sym.isType, sym) // it must be compiling Array[a]
ObjectReference
}
+ /** Interfaces are all treated as AnyRef else we will run into
+ * post-erasure inconsistencies when differing lubs are needed.
+ */
+ private def newReference(sym: Symbol) =
+ if (sym.isInterface || sym.isTrait) ObjectReference
+ else REFERENCE(sym)
private def primitiveOrRefType(sym: Symbol) =
- primitiveTypeMap.getOrElse(sym, REFERENCE(sym))
+ primitiveTypeMap.getOrElse(sym, newReference(sym))
private def primitiveOrClassType(sym: Symbol, targs: List[Type]) =
primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, targs))