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.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23468 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
extempore 2010-11-08 18:12:25 +00:00
parent cc589916bc
commit 748dae76f5
2 changed files with 43 additions and 16 deletions

View File

@ -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

View File

@ -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
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))