aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-02-09 10:03:23 +0100
committerMartin Odersky <odersky@gmail.com>2013-02-09 10:03:23 +0100
commit3debc923154bb5beec8d08b88e8f96ae18ee3734 (patch)
tree8d87997ddfc293ba24f1bba3057c9b7b58d93b7f /src/dotty/tools
parent25e09861e097b8db659ba1fc2d103e540db86a22 (diff)
downloaddotty-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.scala218
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala25
-rw-r--r--src/dotty/tools/dotc/core/Printers.scala51
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala6
-rw-r--r--src/dotty/tools/dotc/core/Types.scala4
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 ------------------------------------------------------