diff options
Diffstat (limited to 'examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/TypeKinds.scala')
-rw-r--r-- | examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/TypeKinds.scala | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/TypeKinds.scala b/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/TypeKinds.scala new file mode 100644 index 0000000..774be68 --- /dev/null +++ b/examples/scala-js/compiler/src/main/scala/scala/scalajs/compiler/TypeKinds.scala @@ -0,0 +1,252 @@ +/* Scala.js compiler + * Copyright 2013 LAMP/EPFL + * @author Sébastien Doeraene + */ + +package scala.scalajs.compiler + +import scala.tools.nsc._ + +import scala.scalajs.ir +import ir.{Definitions, Types} + +/** Glue representation of types as seen from the IR but still with a + * reference to the Symbols. + * + * @author Sébastien Doeraene + */ +trait TypeKinds extends SubComponent { this: GenJSCode => + import global._ + import jsAddons._ + import definitions._ + + lazy val ObjectReference = REFERENCE(definitions.ObjectClass) + + lazy val VoidKind = VOID + lazy val BooleanKind = BOOL + lazy val CharKind = INT(CharClass) + lazy val ByteKind = INT(ByteClass) + lazy val ShortKind = INT(ShortClass) + lazy val IntKind = INT(IntClass) + lazy val LongKind = LONG + lazy val FloatKind = FLOAT(FloatClass) + lazy val DoubleKind = FLOAT(DoubleClass) + + /** TypeKinds for Scala primitive types. */ + lazy val primitiveTypeMap: Map[Symbol, TypeKind] = { + import definitions._ + Map( + UnitClass -> VoidKind, + BooleanClass -> BooleanKind, + CharClass -> CharKind, + ByteClass -> ByteKind, + ShortClass -> ShortKind, + IntClass -> IntKind, + LongClass -> LongKind, + FloatClass -> FloatKind, + DoubleClass -> DoubleKind + ) + } + + /** Glue representation of types as seen from the IR but still with a + * reference to the Symbols. + */ + sealed abstract class TypeKind { + def isReferenceType = false + def isArrayType = false + def isValueType = false + + def toIRType: Types.Type + def toReferenceType: Types.ReferenceType + } + + sealed abstract class TypeKindButArray extends TypeKind { + protected def typeSymbol: Symbol + + override def toReferenceType: Types.ClassType = + Types.ClassType(encodeClassFullName(typeSymbol)) + } + + /** The void, for trees that can only appear in statement position. */ + case object VOID extends TypeKindButArray { + protected def typeSymbol = UnitClass + def toIRType: Types.NoType.type = Types.NoType + } + + sealed abstract class ValueTypeKind extends TypeKindButArray { + override def isValueType = true + + val primitiveCharCode: Char = typeSymbol match { + case BooleanClass => 'Z' + case CharClass => 'C' + case ByteClass => 'B' + case ShortClass => 'S' + case IntClass => 'I' + case LongClass => 'J' + case FloatClass => 'F' + case DoubleClass => 'D' + case x => abort("Unknown primitive type: " + x.fullName) + } + } + + /** Integer number (Byte, Short, Char or Int). */ + case class INT private[TypeKinds] (typeSymbol: Symbol) extends ValueTypeKind { + def toIRType: Types.IntType.type = Types.IntType + } + + /** Long */ + case object LONG extends ValueTypeKind { + protected def typeSymbol = definitions.LongClass + def toIRType: Types.LongType.type = Types.LongType + } + + /** Floating-point number (Float or Double). */ + case class FLOAT private[TypeKinds] (typeSymbol: Symbol) extends ValueTypeKind { + def toIRType: Types.Type = + if (typeSymbol == FloatClass) Types.FloatType + else Types.DoubleType + } + + /** Boolean */ + case object BOOL extends ValueTypeKind { + protected def typeSymbol = definitions.BooleanClass + def toIRType: Types.BooleanType.type = Types.BooleanType + } + + /** Nothing */ + case object NOTHING extends TypeKindButArray { + protected def typeSymbol = definitions.NothingClass + def toIRType: Types.NothingType.type = Types.NothingType + override def toReferenceType: Types.ClassType = + Types.ClassType(Definitions.RuntimeNothingClass) + } + + /** Null */ + case object NULL extends TypeKindButArray { + protected def typeSymbol = definitions.NullClass + def toIRType: Types.NullType.type = Types.NullType + override def toReferenceType: Types.ClassType = + Types.ClassType(Definitions.RuntimeNullClass) + } + + /** An object */ + case class REFERENCE private[TypeKinds] (typeSymbol: Symbol) extends TypeKindButArray { + override def toString(): String = "REFERENCE(" + typeSymbol.fullName + ")" + override def isReferenceType = true + + def toIRType: Types.Type = encodeClassType(typeSymbol) + } + + /** An array */ + case class ARRAY private[TypeKinds] (elem: TypeKind) extends TypeKind { + override def toString = "ARRAY[" + elem + "]" + override def isArrayType = true + + def dimensions: Int = elem match { + case a: ARRAY => a.dimensions + 1 + case _ => 1 + } + + override def toIRType: Types.ArrayType = toReferenceType + + override def toReferenceType: Types.ArrayType = { + Types.ArrayType( + elementKind.toReferenceType.className, + dimensions) + } + + /** The ultimate element type of this array. */ + def elementKind: TypeKindButArray = elem match { + case a: ARRAY => a.elementKind + case k: TypeKindButArray => k + } + } + + ////////////////// Conversions ////////////////////////////// + + def toIRType(t: Type): Types.Type = + toTypeKind(t).toIRType + + def toReferenceType(t: Type): Types.ReferenceType = + toTypeKind(t).toReferenceType + + // The following code is a hard copy-and-paste from backend.icode.TypeKinds + + /** Return the TypeKind of the given type + * + * Call to .normalize fixes #3003 (follow type aliases). Otherwise, + * arrayOrClassType below would return ObjectReference. + */ + def toTypeKind(t: Type): TypeKind = t.normalize match { + case ThisType(ArrayClass) => ObjectReference + case ThisType(sym) => newReference(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. + // !!! Removed in JavaScript backend because I do not know what to do with lub + //case ExistentialType(_, t) => toTypeKind(t) + // Apparently, this case does occur (see pos/CustomGlobal.scala) + case t: AnnotatedType => toTypeKind(t.underlying) + //case RefinedType(parents, _) => parents map toTypeKind reduceLeft lub + + /* This case is not in scalac. We need it for the test + * run/valueclasses-classtag-existential. I have no idea how icode does + * not fail this test: we do everything the same as icode up to here. + */ + case tpe: ErasedValueType => newReference(tpe.valueClazz) + + // 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 = sym match { + case NothingClass => NOTHING + case NullClass => NULL + case _ => + // 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) + REFERENCE(traitSym) + else + REFERENCE(sym) + } else { + 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)) +} |