diff options
author | Martin Odersky <odersky@gmail.com> | 2013-02-09 10:03:23 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-02-09 10:03:23 +0100 |
commit | 3debc923154bb5beec8d08b88e8f96ae18ee3734 (patch) | |
tree | 8d87997ddfc293ba24f1bba3057c9b7b58d93b7f /src/dotty/tools | |
parent | 25e09861e097b8db659ba1fc2d103e540db86a22 (diff) | |
download | dotty-3debc923154bb5beec8d08b88e8f96ae18ee3734.tar.gz dotty-3debc923154bb5beec8d08b88e8f96ae18ee3734.tar.bz2 dotty-3debc923154bb5beec8d08b88e8f96ae18ee3734.zip |
Integration of Constants
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/core/Constants.scala | 218 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 25 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Printers.scala | 51 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 4 |
5 files changed, 260 insertions, 44 deletions
diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala index 94e22cdd4..825ce60f1 100644 --- a/src/dotty/tools/dotc/core/Constants.scala +++ b/src/dotty/tools/dotc/core/Constants.scala @@ -1,12 +1,222 @@ package dotty.tools.dotc package core -import Types._ +import Types._, Symbols._, Contexts._ object Constants { + final val NoTag = 0 + final val UnitTag = 1 + final val BooleanTag = 2 + final val ByteTag = 3 + final val ShortTag = 4 + final val CharTag = 5 + final val IntTag = 6 + final val LongTag = 7 + final val FloatTag = 8 + final val DoubleTag = 9 + final val StringTag = 10 + final val NullTag = 11 + final val ClazzTag = 12 + // For supporting java enumerations inside java annotations (see ClassfileParser) + final val EnumTag = 13 + case class Constant(value: Any) { - def tpe: Type = ??? - } + import java.lang.Double.doubleToRawLongBits + import java.lang.Float.floatToRawIntBits + + val tag: Int = value match { + case null => NullTag + case x: Unit => UnitTag + case x: Boolean => BooleanTag + case x: Byte => ByteTag + case x: Short => ShortTag + case x: Int => IntTag + case x: Long => LongTag + case x: Float => FloatTag + case x: Double => DoubleTag + case x: String => StringTag + case x: Char => CharTag + case x: Type => ClazzTag + case x: Symbol => EnumTag + case _ => throw new Error("bad constant value: " + value + " of class " + value.getClass) + } + + def isByteRange: Boolean = isIntRange && Byte.MinValue <= intValue && intValue <= Byte.MaxValue + def isShortRange: Boolean = isIntRange && Short.MinValue <= intValue && intValue <= Short.MaxValue + def isCharRange: Boolean = isIntRange && Char.MinValue <= intValue && intValue <= Char.MaxValue + def isIntRange: Boolean = ByteTag <= tag && tag <= IntTag + def isLongRange: Boolean = ByteTag <= tag && tag <= LongTag + def isFloatRange: Boolean = ByteTag <= tag && tag <= FloatTag + def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag + def isNonUnitAnyVal = BooleanTag <= tag && tag <= DoubleTag + def isAnyVal = UnitTag <= tag && tag <= DoubleTag + + def tpe(implicit ctx: Context): Type = tag match { + case UnitTag => defn.UnitClass.typeConstructor + case BooleanTag => defn.BooleanClass.typeConstructor + case ByteTag => defn.ByteClass.typeConstructor + case ShortTag => defn.ShortClass.typeConstructor + case CharTag => defn.CharClass.typeConstructor + case IntTag => defn.IntClass.typeConstructor + case LongTag => defn.LongClass.typeConstructor + case FloatTag => defn.FloatClass.typeConstructor + case DoubleTag => defn.DoubleClass.typeConstructor + case StringTag => defn.StringClass.typeConstructor + case NullTag => defn.NullClass.typeConstructor + case ClazzTag => defn.ClassType(typeValue) + case EnumTag => defn.EnumType(symbolValue) + } + + /** We need the equals method to take account of tags as well as values. + */ + override def equals(other: Any): Boolean = other match { + case that: Constant => + this.tag == that.tag && equalHashValue == that.equalHashValue + case _ => false + } + + def isNaN = value match { + case f: Float => f.isNaN + case d: Double => d.isNaN + case _ => false + } + + def booleanValue: Boolean = + if (tag == BooleanTag) value.asInstanceOf[Boolean] + else throw new Error("value " + value + " is not a boolean"); + + def byteValue: Byte = tag match { + case ByteTag => value.asInstanceOf[Byte] + case ShortTag => value.asInstanceOf[Short].toByte + case CharTag => value.asInstanceOf[Char].toByte + case IntTag => value.asInstanceOf[Int].toByte + case LongTag => value.asInstanceOf[Long].toByte + case FloatTag => value.asInstanceOf[Float].toByte + case DoubleTag => value.asInstanceOf[Double].toByte + case _ => throw new Error("value " + value + " is not a Byte") + } + + def shortValue: Short = tag match { + case ByteTag => value.asInstanceOf[Byte].toShort + case ShortTag => value.asInstanceOf[Short] + case CharTag => value.asInstanceOf[Char].toShort + case IntTag => value.asInstanceOf[Int].toShort + case LongTag => value.asInstanceOf[Long].toShort + case FloatTag => value.asInstanceOf[Float].toShort + case DoubleTag => value.asInstanceOf[Double].toShort + case _ => throw new Error("value " + value + " is not a Short") + } + + def charValue: Char = tag match { + case ByteTag => value.asInstanceOf[Byte].toChar + case ShortTag => value.asInstanceOf[Short].toChar + case CharTag => value.asInstanceOf[Char] + case IntTag => value.asInstanceOf[Int].toChar + case LongTag => value.asInstanceOf[Long].toChar + case FloatTag => value.asInstanceOf[Float].toChar + case DoubleTag => value.asInstanceOf[Double].toChar + case _ => throw new Error("value " + value + " is not a Char") + } -}
\ No newline at end of file + def intValue: Int = tag match { + case ByteTag => value.asInstanceOf[Byte].toInt + case ShortTag => value.asInstanceOf[Short].toInt + case CharTag => value.asInstanceOf[Char].toInt + case IntTag => value.asInstanceOf[Int] + case LongTag => value.asInstanceOf[Long].toInt + case FloatTag => value.asInstanceOf[Float].toInt + case DoubleTag => value.asInstanceOf[Double].toInt + case _ => throw new Error("value " + value + " is not an Int") + } + + def longValue: Long = tag match { + case ByteTag => value.asInstanceOf[Byte].toLong + case ShortTag => value.asInstanceOf[Short].toLong + case CharTag => value.asInstanceOf[Char].toLong + case IntTag => value.asInstanceOf[Int].toLong + case LongTag => value.asInstanceOf[Long] + case FloatTag => value.asInstanceOf[Float].toLong + case DoubleTag => value.asInstanceOf[Double].toLong + case _ => throw new Error("value " + value + " is not a Long") + } + + def floatValue: Float = tag match { + case ByteTag => value.asInstanceOf[Byte].toFloat + case ShortTag => value.asInstanceOf[Short].toFloat + case CharTag => value.asInstanceOf[Char].toFloat + case IntTag => value.asInstanceOf[Int].toFloat + case LongTag => value.asInstanceOf[Long].toFloat + case FloatTag => value.asInstanceOf[Float] + case DoubleTag => value.asInstanceOf[Double].toFloat + case _ => throw new Error("value " + value + " is not a Float") + } + + def doubleValue: Double = tag match { + case ByteTag => value.asInstanceOf[Byte].toDouble + case ShortTag => value.asInstanceOf[Short].toDouble + case CharTag => value.asInstanceOf[Char].toDouble + case IntTag => value.asInstanceOf[Int].toDouble + case LongTag => value.asInstanceOf[Long].toDouble + case FloatTag => value.asInstanceOf[Float].toDouble + case DoubleTag => value.asInstanceOf[Double] + case _ => throw new Error("value " + value + " is not a Double") + } + + /** Convert constant value to conform to given type. + */ + def convertTo(pt: Type)(implicit ctx: Context): Constant = { + val target = pt.typeSymbol + if (target == tpe.typeSymbol) + this + else if (target == defn.ByteClass && isByteRange) + Constant(byteValue) + else if (target == defn.ShortClass && isShortRange) + Constant(shortValue) + else if (target == defn.CharClass && isCharRange) + Constant(charValue) + else if (target == defn.IntClass && isIntRange) + Constant(intValue) + else if (target == defn.LongClass && isLongRange) + Constant(longValue) + else if (target == defn.FloatClass && isFloatRange) + Constant(floatValue) + else if (target == defn.DoubleClass && isNumeric) + Constant(doubleValue) + else + null + } + + def stringValue: String = value.toString + + def show(implicit ctx: Context) = ctx.show(this) + + def typeValue: Type = value.asInstanceOf[Type] + def symbolValue: Symbol = value.asInstanceOf[Symbol] + + /** + * Consider two `NaN`s to be identical, despite non-equality + * Consider -0d to be distinct from 0d, despite equality + * + * We use the raw versions (i.e. `floatToRawIntBits` rather than `floatToIntBits`) + * to avoid treating different encodings of `NaN` as the same constant. + * You probably can't express different `NaN` varieties as compile time + * constants in regular Scala code, but it is conceivable that you could + * conjure them with a macro. + */ + private def equalHashValue: Any = value match { + case f: Float => floatToRawIntBits(f) + case d: Double => doubleToRawLongBits(d) + case v => v + } + + override def hashCode: Int = { + import scala.util.hashing.MurmurHash3._ + val seed = 17 + var h = seed + h = mix(h, tag.##) // include tag in the hash, otherwise 0, 0d, 0L, 0f collide. + h = mix(h, equalHashValue.##) + finalizeHash(h, length = 2) + } + } +} diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 769f108f7..b399a77c4 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -107,6 +107,18 @@ class Definitions(implicit ctx: Context) { lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS, Contravariant, AnyRefType, ArrayType) lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, AnyRefType, SeqType) + // fundamental reference classes + lazy val PartialFunctionClass = requiredClass("scala.PartialFunction") + lazy val AbstractPartialFunctionClass = requiredClass("scala.runtime.AbstractPartialFunction") + lazy val SymbolClass = requiredClass("scala.Symbol") + lazy val StringClass = requiredClass("java.lang.String") + lazy val ClassClass = requiredClass("java.lang.Class") + //def Class_getMethod = getMemberMethod(ClassClass, nme.getMethod_) + lazy val DynamicClass = requiredClass("scala.Dynamic") + lazy val BoxedNumberClass = requiredClass("java.lang.Number") + lazy val JavaSerializableClass = requiredClass("java.lang.Serializable") + lazy val ComparableClass = requiredClass("java.lang.Comparable") + lazy val AnyType = AnyClass.typeConstructor lazy val AnyValType = AnyValClass.typeConstructor lazy val ObjectType = ObjectClass.typeConstructor @@ -117,10 +129,17 @@ class Definitions(implicit ctx: Context) { lazy val SeqType = SeqClass.typeConstructor lazy val ArrayType = ArrayClass.typeConstructor + def ClassType(arg: Type)(implicit ctx: Context) = { + val ctype = ClassClass.typeConstructor + if (ctx.phase.erasedTypes) ctype else ctype.appliedTo(arg) + } - lazy val BoxedNumberClass = requiredClass("java.lang.Number") - lazy val JavaSerializableClass = requiredClass("java.lang.Serializable") - lazy val ComparableClass = requiredClass("java.lang.Comparable") + def EnumType(sym: Symbol)(implicit ctx: Context) = + // given (in java): "class A { enum E { VAL1 } }" + // - sym: the symbol of the actual enumeration value (VAL1) + // - .owner: the ModuleClassSymbol of the enumeration (object E) + // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) + sym.owner.linkedClass.typeConstructor // ----- Class sets --------------------------------------------------- diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala index 44a647f50..1796be217 100644 --- a/src/dotty/tools/dotc/core/Printers.scala +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -10,8 +10,6 @@ trait Printers { this: Context => import Printers._ - def show(tp: Type): String = printer(this).show(tp, GlobalPrec) - private var _diagnostics: Option[StringBuilder] = _ protected def diagnostics_=(diagnostics: Option[StringBuilder]) = _diagnostics = diagnostics @@ -242,18 +240,6 @@ object Printers { protected def isEmptyPrefix(sym: Symbol) = sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName - @switch private def escapedChar(ch: Char): String = ch match { - case '\b' => "\\b" - case '\t' => "\\t" - case '\n' => "\\n" - case '\f' => "\\f" - case '\r' => "\\r" - case '"' => "\\\"" - case '\'' => "\\\'" - case '\\' => "\\\\" - case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch) - } - /** The string representation of this type used as a prefix */ protected def showPrefix(tp: Type): String = controlled { tp match { @@ -365,23 +351,25 @@ object Printers { def showLocated(sym: Symbol): String = show(sym) + showLocation(sym) - def show(const: Constant) = { - ??? /* - def escape(text: String): String = text flatMap escapedChar - tag match { - case NullTag => "null" - case StringTag => "\"" + escape(stringValue) + "\"" - case ClazzTag => - def show(tpe: Type) = "classOf[" + signature(tpe) + "]" - typeValue match { - case ErasedValueType(orig) => show(orig) - case _ => show(typeValue) - } - case CharTag => "'" + escapedChar(charValue) + "'" - case LongTag => longValue.toString() + "L" - case EnumTag => symbolValue.name.toString() - case _ => String.valueOf(value) - }*/ + @switch private def escapedChar(ch: Char): String = ch match { + case '\b' => "\\b" + case '\t' => "\\t" + case '\n' => "\\n" + case '\f' => "\\f" + case '\r' => "\\r" + case '"' => "\\\"" + case '\'' => "\\\'" + case '\\' => "\\\\" + case _ => if (ch.isControl) "\\0" + toOctalString(ch) else String.valueOf(ch) + } + + def show(const: Constant) = const.tag match { + case StringTag => "\"" + (const.value.toString flatMap escapedChar) + "\"" + case ClazzTag => s"classOf[${const.tpe.show}]" + case CharTag => s"'${escapedChar(const.charValue)}'" + case LongTag => const.longValue.toString + "L" + case EnumTag => const.symbolValue.name.toString + case _ => String.valueOf(const.value) } def show(annot: Annotation): String = ??? @@ -391,7 +379,6 @@ object Printers { def show(sc: Scope): String = "Scope{\n" + show(sc.toList, ";\n ") + "\n}" - } class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 0610acb02..a53ac374f 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -218,12 +218,12 @@ object SymDenotations { /** Is this a subclass of the given class `base`? */ def isSubClass(base: Symbol)(implicit ctx: Context) = false + /** Is this a user defined "def" method? Excluded are accessors and stable values */ + def isSourceMethod = this is (Method, butNot = Accessor) + /** Is this a setter? */ def isGetter = (this is Accessor) && !originalName.isSetterName - /** Is this a user defined "def" method? Excluded are accessors and stable values */ - def isSourceMethod = this is (Method, butNot = Accessor | Stable) - /** Is this a setter? */ def isSetter = (this is Accessor) && originalName.isSetterName diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index aca1aef1d..19d254b93 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -390,7 +390,7 @@ object Types { /** Widen from constant type to its underlying non-constant * base type. */ - final def deconst: Type = this match { + final def deconst(implicit ctx: Context): Type = this match { case tp: ConstantType => tp.value.tpe case _ => this } @@ -516,7 +516,7 @@ object Types { def |(that: Type)(implicit ctx: Context): Type = ctx.lub(this, that) - def show(implicit ctx: Context): String = ctx.show(this) + def show(implicit ctx: Context): String = ctx.show(this, Printers.GlobalPrec) // ----- hashing ------------------------------------------------------ |