summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Suereth <Joshua.Suereth@gmail.com>2012-09-14 09:32:57 -0700
committerJosh Suereth <Joshua.Suereth@gmail.com>2012-09-14 09:32:57 -0700
commite9c01dd1cedf15c946c03ef1e9d23ef6db275f2b (patch)
tree0e78b0e553036c45bdb24049544f3e75a84627e2 /src
parent7bafb210a18f7b73b26a199e13f9f8cbb6f28e96 (diff)
parent21bd081540413a8625247d2e40506112cc1ea218 (diff)
downloadscala-e9c01dd1cedf15c946c03ef1e9d23ef6db275f2b.tar.gz
scala-e9c01dd1cedf15c946c03ef1e9d23ef6db275f2b.tar.bz2
scala-e9c01dd1cedf15c946c03ef1e9d23ef6db275f2b.zip
Merge pull request #1271 from retronym/ticket/6331
SI-6331 deconst If type / refine equality of floating point Constant types.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--src/partest/scala/tools/partest/package.scala27
-rw-r--r--src/reflect/scala/reflect/internal/Constants.scala32
3 files changed, 57 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 738dde7895..d0722f7b98 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4086,7 +4086,7 @@ trait Typers extends Modes with Adaptations with Tags {
if ( opt.virtPatmat && !isPastTyper
&& thenp1.tpe.annotations.isEmpty && elsep1.tpe.annotations.isEmpty // annotated types need to be lubbed regardless (at least, continations break if you by pass them like this)
&& thenTp =:= elseTp
- ) (thenp1.tpe, false) // use unpacked type
+ ) (thenp1.tpe.deconst, false) // use unpacked type. Important to deconst, as is done in ptOrLub, otherwise `if (???) 0 else 0` evaluates to 0 (SI-6331)
// TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala
else ptOrLub(thenp1.tpe :: elsep1.tpe :: Nil, pt)
diff --git a/src/partest/scala/tools/partest/package.scala b/src/partest/scala/tools/partest/package.scala
index 08934ef143..49d3ed301c 100644
--- a/src/partest/scala/tools/partest/package.scala
+++ b/src/partest/scala/tools/partest/package.scala
@@ -73,4 +73,31 @@ package object partest {
def isPartestDebug: Boolean =
propOrEmpty("partest.debug") == "true"
+
+
+ import language.experimental.macros
+
+ /**
+ * `trace("".isEmpty)` will return `true` and as a side effect print the following to standard out.
+ * {{{
+ * trace> "".isEmpty
+ * res: Boolean = true
+ *
+ * }}}
+ *
+ * An alternative to [[scala.tools.partest.ReplTest]] that avoids the inconvenience of embedding
+ * test code in a string.
+ */
+ def trace[A](a: A) = macro traceImpl[A]
+
+ import scala.reflect.macros.Context
+ def traceImpl[A: c.AbsTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = {
+ import c.universe._
+ val exprCode = c.literal(show(a.tree))
+ val exprType = c.literal(show(a.actualType))
+ reify {
+ println(s"trace> ${exprCode.splice}\nres: ${exprType.splice} = ${a.splice}\n")
+ a.splice
+ }
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Constants.scala b/src/reflect/scala/reflect/internal/Constants.scala
index e5a543da46..b434be64a3 100644
--- a/src/reflect/scala/reflect/internal/Constants.scala
+++ b/src/reflect/scala/reflect/internal/Constants.scala
@@ -31,6 +31,9 @@ trait Constants extends api.Constants {
final val EnumTag = 13
case class Constant(value: Any) extends ConstantApi {
+ import java.lang.Double.doubleToRawLongBits
+ import java.lang.Float.floatToRawIntBits
+
val tag: Int = value match {
case null => NullTag
case x: Unit => UnitTag
@@ -81,10 +84,10 @@ trait Constants extends api.Constants {
/** We need the equals method to take account of tags as well as values.
*/
+ // !!! In what circumstance could `equalHashValue == that.equalHashValue && tag != that.tag` be true?
override def equals(other: Any): Boolean = other match {
case that: Constant =>
- this.tag == that.tag &&
- (this.value == that.value || this.isNaN && that.isNaN)
+ this.tag == that.tag && equalHashValue == that.equalHashValue
case _ => false
}
@@ -236,7 +239,30 @@ trait Constants extends api.Constants {
def typeValue: Type = value.asInstanceOf[Type]
def symbolValue: Symbol = value.asInstanceOf[Symbol]
- override def hashCode: Int = value.## * 41 + 17
+ /**
+ * 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)
+ }
}
object Constant extends ConstantExtractor