dotty.tools.dotc.core.Constants.scala Maven / Gradle / Ivy
The newest version!
package dotty.tools.dotc
package core
import Types._, Symbols._, Contexts._
import printing.Printer
import printing.Texts.Text
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
class Constant(val value: Any, val tag: Int) extends printing.Showable with Product1[Any] {
import java.lang.Double.doubleToRawLongBits
import java.lang.Float.floatToRawIntBits
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: Boolean = BooleanTag <= tag && tag <= DoubleTag
def isAnyVal: Boolean = UnitTag <= tag && tag <= DoubleTag
def tpe(implicit ctx: Context): Type = tag match {
case UnitTag => defn.UnitType
case BooleanTag => defn.BooleanType
case ByteTag => defn.ByteType
case ShortTag => defn.ShortType
case CharTag => defn.CharType
case IntTag => defn.IntType
case LongTag => defn.LongType
case FloatTag => defn.FloatType
case DoubleTag => defn.DoubleType
case StringTag => defn.StringType
case NullTag => defn.NullType
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: Boolean = 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")
}
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 = {
def classBound(pt: Type): Type = pt.dealias.stripTypeVar match {
case tref: TypeRef if !tref.symbol.isClass && tref.info.exists =>
classBound(tref.info.bounds.lo)
case param: TypeParamRef =>
ctx.typerState.constraint.entry(param) match {
case TypeBounds(lo, hi) =>
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
else classBound(lo)
case NoType => classBound(param.binder.paramInfos(param.paramNum).lo)
case inst => classBound(inst)
}
case pt => pt
}
val target = classBound(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 toText(printer: Printer): Text = printer.toText(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)
}
override def toString: String = s"Constant($value)"
def canEqual(x: Any): Boolean = true
def get: Any = value
def isEmpty: Boolean = false
def _1: Any = value
}
object Constant {
def apply(x: Null): Constant = new Constant(x, NullTag)
def apply(x: Unit): Constant = new Constant(x, UnitTag)
def apply(x: Boolean): Constant = new Constant(x, BooleanTag)
def apply(x: Byte): Constant = new Constant(x, ByteTag)
def apply(x: Short): Constant = new Constant(x, ShortTag)
def apply(x: Int): Constant = new Constant(x, IntTag)
def apply(x: Long): Constant = new Constant(x, LongTag)
def apply(x: Float): Constant = new Constant(x, FloatTag)
def apply(x: Double): Constant = new Constant(x, DoubleTag)
def apply(x: String): Constant = new Constant(x, StringTag)
def apply(x: Char): Constant = new Constant(x, CharTag)
def apply(x: Type): Constant = new Constant(x, ClazzTag)
def apply(x: Symbol): Constant = new Constant(x, EnumTag)
def apply(value: Any): Constant =
new Constant(value,
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
}
)
def unapply(c: Constant): Constant = c
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy