diff options
author | Paul Phillips <paulp@improving.org> | 2009-10-28 20:10:54 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-10-28 20:10:54 +0000 |
commit | b7772a6535b1d3989ad350069568b124619f2877 (patch) | |
tree | 56726bf0a76929fc69bcf059e68e6e7fb2632ce1 /src/compiler | |
parent | cc934ee7bb181645d4436eb923f7eb843b7c259d (diff) | |
download | scala-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.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 44 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala | 6 |
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 |