diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala | 438 |
1 files changed, 0 insertions, 438 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala deleted file mode 100644 index a6d0d3b9fa..0000000000 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ /dev/null @@ -1,438 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package backend -package icode - -/* A type case - - case UNIT => - case BOOL => - case BYTE => - case SHORT => - case CHAR => - case INT => - case LONG => - case FLOAT => - case DOUBLE => - case REFERENCE(cls) => - case ARRAY(elem) => - -*/ - -trait TypeKinds { self: ICodes => - import global._ - import definitions.{ ArrayClass, AnyRefClass, ObjectClass, NullClass, NothingClass, arrayType } - - /** A map from scala primitive Types to ICode TypeKinds */ - lazy val primitiveTypeMap: Map[Symbol, TypeKind] = { - import definitions._ - Map( - UnitClass -> UNIT, - BooleanClass -> BOOL, - CharClass -> CHAR, - ByteClass -> BYTE, - ShortClass -> SHORT, - IntClass -> INT, - LongClass -> LONG, - FloatClass -> FLOAT, - DoubleClass -> DOUBLE - ) - } - /** Reverse map for toType */ - private lazy val reversePrimitiveMap: Map[TypeKind, Symbol] = - (primitiveTypeMap map (_.swap)).toMap - - /** This class represents a type kind. Type kinds - * represent the types that the VM know (or the ICode - * view of what VMs know). - */ - sealed abstract class TypeKind { - def maxType(other: TypeKind): TypeKind - - 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 isReferenceType = false - def isArrayType = false - def isValueType = false - def isBoxedType = false - final def isRefOrArrayType = isReferenceType || isArrayType - final def isNothingType = this == NothingReference - final def isNullType = this == NullReference - final def isInterfaceType = this match { - case REFERENCE(cls) if cls.isInterface || cls.isTrait => true - case _ => false - } - - /** On the JVM, - * BOOL, BYTE, CHAR, SHORT, and INT - * are like Ints for the purposes of calculating the lub. - */ - def isIntSizedType: Boolean = false - - /** On the JVM, similar to isIntSizedType except that BOOL isn't integral while LONG is. */ - def isIntegralType: Boolean = false - - /** On the JVM, FLOAT and DOUBLE. */ - def isRealType: Boolean = false - - final def isNumericType: Boolean = isIntegralType | isRealType - - /** Simple subtyping check */ - def <:<(other: TypeKind): Boolean - - /** - * this is directly assignable to other if no coercion or - * casting is needed to convert this to other. It's a distinct - * relationship from <:< because on the JVM, BOOL, BYTE, CHAR, - * SHORT need no coercion to INT even though JVM arrays - * are covariant, ARRAY[SHORT] is not a subtype of ARRAY[INT] - */ - final def isAssignabledTo(other: TypeKind): Boolean = other match { - case INT => this.isIntSizedType - case _ => this <:< other - } - - /** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */ - def isWideType: Boolean = false - - /** The number of dimensions for array types. */ - def dimensions: Int = 0 - - protected def uncomparable(thisKind: String, other: TypeKind): Nothing = - abort("Uncomparable type kinds: " + thisKind + " with " + other) - - protected def uncomparable(other: TypeKind): Nothing = - uncomparable(this.toString, other) - } - - sealed abstract class ValueTypeKind extends TypeKind { - override def isValueType = true - override def toString = { - this.getClass.getName stripSuffix "$" dropWhile (_ != '$') drop 1 - } - def <:<(other: TypeKind): Boolean = this eq other - } - - /** - * The least upper bound of two typekinds. They have to be either - * REFERENCE or ARRAY kinds. - * - * The lub is based on the lub of scala types. - */ - def lub(a: TypeKind, b: TypeKind): TypeKind = { - /* 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 = enteringUncurry { - val tp = global.lub(List(tk1.toType, tk2.toType)) - val (front, rest) = tp.parents span (_.typeSymbol.isTrait) - - if (front.isEmpty || rest.isEmpty || rest.head.typeSymbol == ObjectClass) tp - else rest.head - } - - def isIntLub = ( - (a == INT && b.isIntSizedType) || - (b == INT && a.isIntSizedType) - ) - - if (a == b) a - else if (a.isNothingType) b - else if (b.isNothingType) a - else if (a.isBoxedType || b.isBoxedType) AnyRefReference // we should do better - else if (isIntLub) INT - else if (a.isRefOrArrayType && b.isRefOrArrayType) { - if (a.isNullType) b - else if (b.isNullType) a - else toTypeKind(lub0(a, b)) - } - else throw new CheckerException("Incompatible types: " + a + " with " + b) - } - - /** The unit value */ - case object UNIT extends ValueTypeKind { - def maxType(other: TypeKind) = other match { - case UNIT | REFERENCE(NothingClass) => UNIT - case _ => uncomparable(other) - } - } - - /** A boolean value */ - case object BOOL extends ValueTypeKind { - override def isIntSizedType = true - def maxType(other: TypeKind) = other match { - case BOOL | REFERENCE(NothingClass) => BOOL - case _ => uncomparable(other) - } - } - - /** Note that the max of Char/Byte and Char/Short is Int, because - * neither strictly encloses the other due to unsignedness. - * See ticket #2087 for a consequence. - */ - - /** A 1-byte signed integer */ - case object BYTE extends ValueTypeKind { - override def isIntSizedType = true - override def isIntegralType = true - def maxType(other: TypeKind) = { - if (other == BYTE || other.isNothingType) BYTE - else if (other == CHAR) INT - else if (other.isNumericType) other - else uncomparable(other) - } - } - - /** A 2-byte signed integer */ - case object SHORT extends ValueTypeKind { - override def isIntSizedType = true - override def isIntegralType = true - override def maxType(other: TypeKind) = other match { - case BYTE | SHORT | REFERENCE(NothingClass) => SHORT - case CHAR => INT - case INT | LONG | FLOAT | DOUBLE => other - case _ => uncomparable(other) - } - } - - /** A 2-byte UNSIGNED integer */ - case object CHAR extends ValueTypeKind { - override def isIntSizedType = true - override def isIntegralType = true - override def maxType(other: TypeKind) = other match { - case CHAR | REFERENCE(NothingClass) => CHAR - case BYTE | SHORT => INT - case INT | LONG | FLOAT | DOUBLE => other - case _ => uncomparable(other) - } - } - - /** A 4-byte signed integer */ - case object INT extends ValueTypeKind { - override def isIntSizedType = true - override def isIntegralType = true - override def maxType(other: TypeKind) = other match { - case BYTE | SHORT | CHAR | INT | REFERENCE(NothingClass) => INT - case LONG | FLOAT | DOUBLE => other - case _ => uncomparable(other) - } - } - - /** An 8-byte signed integer */ - case object LONG extends ValueTypeKind { - override def isIntegralType = true - override def isWideType = true - override def maxType(other: TypeKind): TypeKind = - if (other.isIntegralType || other.isNothingType) LONG - else if (other.isRealType) DOUBLE - else uncomparable(other) - } - - /** A 4-byte floating point number */ - case object FLOAT extends ValueTypeKind { - override def isRealType = true - override def maxType(other: TypeKind): TypeKind = - if (other == DOUBLE) DOUBLE - else if (other.isNumericType || other.isNothingType) FLOAT - else uncomparable(other) - } - - /** An 8-byte floating point number */ - case object DOUBLE extends ValueTypeKind { - override def isRealType = true - override def isWideType = true - override def maxType(other: TypeKind): TypeKind = - if (other.isNumericType || other.isNothingType) DOUBLE - else uncomparable(other) - } - - /** A class type. */ - final case class REFERENCE(cls: Symbol) extends TypeKind { - override def toString = "REF(" + cls + ")" - assert(cls ne null, - "REFERENCE to null class symbol.") - assert(cls != ArrayClass, - "REFERENCE to Array is not allowed, should be ARRAY[..] instead") - assert(cls != NoSymbol, - "REFERENCE to NoSymbol not allowed!") - - /** - * Approximate `lub`. The common type of two references is - * always AnyRef. For 'real' least upper bound wrt to subclassing - * use method 'lub'. - */ - override def maxType(other: TypeKind) = other match { - case REFERENCE(_) | ARRAY(_) => AnyRefReference - case _ => uncomparable("REFERENCE", other) - } - - /** Checks subtyping relationship. */ - def <:<(other: TypeKind) = isNothingType || (other match { - case REFERENCE(cls2) => cls.tpe <:< cls2.tpe - case ARRAY(_) => cls == NullClass - case _ => false - }) - override def isReferenceType = true - } - - def ArrayN(elem: TypeKind, dims: Int): ARRAY = { - assert(dims > 0) - if (dims == 1) ARRAY(elem) - else ARRAY(ArrayN(elem, dims - 1)) - } - - final case class ARRAY(elem: TypeKind) extends TypeKind { - override def toString = "ARRAY[" + elem + "]" - override def isArrayType = true - override def dimensions = 1 + elem.dimensions - - /** The ultimate element type of this array. */ - def elementKind: TypeKind = elem match { - case a @ ARRAY(_) => a.elementKind - case k => k - } - - /** - * Approximate `lub`. The common type of two references is - * always AnyRef. For 'real' least upper bound wrt to subclassing - * use method 'lub'. - */ - override def maxType(other: TypeKind) = other match { - case ARRAY(elem2) if elem == elem2 => ARRAY(elem) - case ARRAY(_) | REFERENCE(_) => AnyRefReference - case _ => uncomparable("ARRAY", other) - } - - /** Array subtyping is covariant, as in Java. Necessary for checking - * code that interacts with Java. */ - def <:<(other: TypeKind) = other match { - case ARRAY(elem2) => elem <:< elem2 - case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent! - case _ => false - } - } - - /** A boxed value. */ - case class BOXED(kind: TypeKind) extends TypeKind { - override def isBoxedType = true - - override def maxType(other: TypeKind) = other match { - case BOXED(`kind`) => this - case REFERENCE(_) | ARRAY(_) | BOXED(_) => AnyRefReference - case _ => uncomparable("BOXED", other) - } - - /** Checks subtyping relationship. */ - def <:<(other: TypeKind) = other match { - case BOXED(`kind`) => true - case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent! - case _ => false - } - } - - /** - * Dummy TypeKind to represent the ConcatClass in a platform-independent - * way. For JVM it would have been a REFERENCE to 'StringBuffer'. - */ - case object ConcatClass extends TypeKind { - override def toString = "ConcatClass" - def <:<(other: TypeKind): Boolean = this eq other - - /** - * Approximate `lub`. The common type of two references is - * always AnyRef. For 'real' least upper bound wrt to subclassing - * use method 'lub'. - */ - override def maxType(other: TypeKind) = other match { - case REFERENCE(_) => AnyRefReference - case _ => uncomparable(other) - } - } - - ////////////////// Conversions ////////////////////////////// - - /** Return the TypeKind of the given type - * - * Call to dealiasWiden fixes #3003 (follow type aliases). Otherwise, - * arrayOrClassType below would return ObjectReference. - */ - def toTypeKind(t: Type): TypeKind = t.dealiasWiden match { - case ThisType(ArrayClass) => ObjectReference - case ThisType(sym) => REFERENCE(sym) - case SingleType(_, sym) => primitiveOrRefType(sym) - case ConstantType(_) => toTypeKind(t.underlying) - case TypeRef(_, sym, args) => primitiveOrClassType(sym, args) - case ClassInfoType(_, _, ArrayClass) => abort("ClassInfoType to ArrayClass!") - case ClassInfoType(_, _, sym) => primitiveOrRefType(sym) - - // !!! Iulian says types which make no sense after erasure should not reach here, - // which includes the ExistentialType, AnnotatedType, RefinedType. I don't know - // if the first two cases exist because they do or as a defensive measure, but - // at the time I added it, RefinedTypes were indeed reaching here. - case ExistentialType(_, t) => toTypeKind(t) - case AnnotatedType(_, t) => toTypeKind(t) - case RefinedType(parents, _) => parents map toTypeKind reduceLeft lub - // For sure WildcardTypes shouldn't reach here either, but when - // debugging such situations this may come in handy. - // case WildcardType => REFERENCE(ObjectClass) - case norm => abort( - "Unknown type: %s, %s [%s, %s] TypeRef? %s".format( - t, norm, t.getClass, norm.getClass, t.isInstanceOf[TypeRef] - ) - ) - } - - /** Return the type kind of a class, possibly an array type. - */ - private def arrayOrClassType(sym: Symbol, targs: List[Type]) = sym match { - case ArrayClass => ARRAY(toTypeKind(targs.head)) - case _ if sym.isClass => newReference(sym) - case _ => - assert(sym.isType, sym) // it must be compiling Array[a] - ObjectReference - } - /** Interfaces have to be handled delicately to avoid introducing - * spurious errors, but if we treat them all as AnyRef we lose too - * much information. - */ - private def newReference(sym: Symbol): TypeKind = { - // Can't call .toInterface (at this phase) or we trip an assertion. - // See PackratParser#grow for a method which fails with an apparent mismatch - // between "object PackratParsers$class" and "trait PackratParsers" - if (sym.isImplClass) { - // pos/spec-List.scala is the sole failure if we don't check for NoSymbol - val traitSym = sym.owner.info.decl(tpnme.interfaceName(sym.name)) - if (traitSym != NoSymbol) - return REFERENCE(traitSym) - } - REFERENCE(sym) - } - - private def primitiveOrRefType(sym: Symbol) = - primitiveTypeMap.getOrElse(sym, newReference(sym)) - private def primitiveOrClassType(sym: Symbol, targs: List[Type]) = - primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, targs)) -} |