summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-10-28 20:10:54 +0000
committerPaul Phillips <paulp@improving.org>2009-10-28 20:10:54 +0000
commitb7772a6535b1d3989ad350069568b124619f2877 (patch)
tree56726bf0a76929fc69bcf059e68e6e7fb2632ce1 /src/compiler
parentcc934ee7bb181645d4436eb923f7eb843b7c259d (diff)
downloadscala-b7772a6535b1d3989ad350069568b124619f2877.tar.gz
scala-b7772a6535b1d3989ad350069568b124619f2877.tar.bz2
scala-b7772a6535b1d3989ad350069568b124619f2877.zip
Whole bunch of code for people interested in eq...
Whole bunch of code for people interested in equality. This includes four command line options you can use to alter equality semantics and the various levels of babbling and panicking which the runtime has to offer when confronted with a boxed primitive comparison.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala12
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala44
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala6
3 files changed, 29 insertions, 33 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index e1429b1644..eb6017815a 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -825,8 +825,6 @@ trait ScalacSettings {
withHelpSyntax("-Ysqueeze:<enabled>")
val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics")
val stop = PhasesSetting ("-Ystop", "Stop after phase")
- val logEquality = BooleanSetting ("-Ylog-equality", "Log all noteworthy equality tests (hardcoded to /tmp/scala-equality-log.txt)") .
- withPostSetHook(() => scala.runtime.Equality.logEverything = true)
val refinementMethodDispatch =
ChoiceSetting ("-Ystruct-dispatch", "Selects dispatch method for structural refinement method calls",
List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") .
@@ -838,6 +836,16 @@ trait ScalacSettings {
val Ypmatdebug = BooleanSetting ("-Ypmat-debug", "Trace all pattern matcher activity.")
val Ytailrec = BooleanSetting ("-Ytailrecommend", "Alert methods which would be tail-recursive if private or final.")
+ // Equality specific
+ val logEqEq = BooleanSetting ("-Ylog-eqeq", "Log all noteworthy equality tests") .
+ withPostSetHook(() => scala.runtime.Equality.logEverything = true)
+ val YfutureEqEq = BooleanSetting ("-Yfuture-eqeq", "Use proposed overloading-based numeric equality semantics.") .
+ withPostSetHook(() => scala.runtime.Equality.use28Semantics = true)
+ val YwarnEqEq = BooleanSetting ("-Ywarn-eqeq", "Warn when boxed primitives of different types are compared.") .
+ withPostSetHook(() => scala.runtime.Equality.warnOnBoxedCompare = true)
+ val YdieEqEq = BooleanSetting ("-Ydie-changed-eqeq", "Throw an exception if a comparison would have come back differently in scala 2.7.") .
+ withPostSetHook(() => scala.runtime.Equality.dieOnBoxedCompareIfValuesAreEqual = true)
+
// Warnings
val Xwarninit = BooleanSetting ("-Xwarninit", "Warn about possible changes in initialization semantics")
val Xchecknull = BooleanSetting ("-Xcheck-null", "Emit warning on selection of nullable reference")
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index b3d7da8f06..99f0d4cf3c 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -1291,7 +1291,7 @@ abstract class GenICode extends SubComponent {
elseCtx: Context): Unit =
{
def genComparisonOp(l: Tree, r: Tree, code: Int) {
- if (settings.logEquality.value && isUniversalEqualityOp(code))
+ if (settings.logEqEq.value && isUniversalEqualityOp(code))
logEqEq(tree, l, r, code)
val op: TestOp = code match {
@@ -1422,9 +1422,13 @@ abstract class GenICode extends SubComponent {
(rsym == ObjectClass) ||
(lsym != rsym) && (isBoxed(lsym) || isBoxed(rsym))
}
+ def cannotAvoidBoxesRuntime =
+ settings.logEqEq.value || settings.YwarnEqEq.value || settings.YdieEqEq.value
- if (mustUseAnyComparator) {
-
+ /** We can avoid generating calls to BoxesRuntime only if -Yfuture-eqeq
+ * is enabled AND none of the eqeq logging options are enabled.
+ */
+ if (mustUseAnyComparator && (!settings.YfutureEqEq.value || cannotAvoidBoxesRuntime)) {
val ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS)
ctx2.bb.emitOnly(
@@ -1433,7 +1437,6 @@ abstract class GenICode extends SubComponent {
)
}
else {
-
if (isNull(l))
// null == expr -> expr eq null
genLoad(r, ctx, ANY_REF_CLASS).bb emitOnly CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)
@@ -2153,39 +2156,18 @@ abstract class GenICode extends SubComponent {
override def varsInScope: Buffer[Local] = new ListBuffer
}
- /** Log equality tests to file if they are playing with typefire */
+ /** Log equality tests between different primitives. */
def logEqEq(tree: Tree, l: Tree, r: Tree, code: Int) {
import definitions._
val op = if (code == scalaPrimitives.EQ) "==" else if (code == scalaPrimitives.NE) "!=" else "??"
-
- def mayBeNumericComparison: Boolean = {
- def isPossiblyBoxed(sym: Symbol): Boolean = {
- import definitions._
- // classes as which a boxed primitive may statically appear
- val possibleBoxes = List(BoxedNumberClass, BoxedCharacterClass, SerializableClass, ComparableClass)
-
- (sym == ObjectClass) || (possibleBoxes exists (sym isNonBottomSubClass _))
- }
-
- val lsym = l.tpe.typeSymbol
- val rsym = r.tpe.typeSymbol
-
- def isSameBox = {
- def isFinalBox(s: Symbol) = (s isNonBottomSubClass BoxedNumberClass) && s.isFinal
- isFinalBox(lsym) && isFinalBox(rsym) && lsym == rsym
- }
- isPossiblyBoxed(lsym) && isPossiblyBoxed(rsym) && !isSameBox
- }
-
val tkl = toTypeKind(l.tpe)
val tkr = toTypeKind(r.tpe)
- lazy val whereAreWe = tree.pos.source + ":" + tree.pos.line
- def logit(preface: String) =
- runtime.Equality.log("[%s] %s %s %s (%s)".format(preface, l.tpe, op, r.tpe, whereAreWe))
if (tkl.isNumericType && tkr.isNumericType && tkl != tkr)
- logit(" KNOWN ")
- else if (mayBeNumericComparison)
- logit("UNKNOWN")
+ runtime.Equality.logComparison(
+ "Comparing actual primitives",
+ "%s %s %s".format(l.tpe, op, r.tpe),
+ tree.pos.source + ":" + tree.pos.line
+ )
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
index a46a987bb8..12f6f4021b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
@@ -70,6 +70,12 @@ abstract class ConstantFolder {
}
private def foldBinop(op: Name, x: Constant, y: Constant): Constant = try {
+ // temporarily logging folded ==/!= so the log doesn't have unexplained absences
+ if ((op == nme.EQ || op == nme.NE) && x.tag != y.tag && settings.logEqEq.value) {
+ val opstr = if (op == nme.EQ) "==" else "!="
+ scala.runtime.Equality.log("Folding constant expression (%s %s %s)".format(x.value, opstr, y.value))
+ }
+
val optag = if (x.tag == y.tag) x.tag
else if (isNumeric(x.tag) && isNumeric(y.tag))
if (x.tag > y.tag) x.tag else y.tag