From 971358bf0a90d7bbb6af7cc34eb282e9ade66460 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Tue, 28 Jan 2014 17:19:49 -0800 Subject: SI-4577 singleton type pattern test should use `eq`, not `==` I find it hard to imagine anyone is relying on `case x: foo.type =>` erroneously being compiled to `foo == x` instead of the spec'ed `foo eq x`, so let's finally fix this. --- .../tools/nsc/transform/patmat/MatchAnalysis.scala | 3 +- .../nsc/transform/patmat/MatchTreeMaking.scala | 3 +- test/files/run/t4577.scala | 38 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 test/files/run/t4577.scala diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index 2a3c631a66..dc4969be43 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -261,7 +261,8 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT } def nonNullTest(testedBinder: Symbol) = uniqueNonNullProp(binderToUniqueTree(testedBinder)) def equalsTest(pat: Tree, testedBinder: Symbol) = uniqueEqualityProp(binderToUniqueTree(testedBinder), unique(pat)) - def eqTest(pat: Tree, testedBinder: Symbol) = uniqueEqualityProp(binderToUniqueTree(testedBinder), unique(pat)) // TODO: eq, not == + // rewrite eq test to type test against the singleton type `pat.tpe`; unrelated to == (uniqueEqualityProp), could be null + def eqTest(pat: Tree, testedBinder: Symbol) = uniqueTypeProp(binderToUniqueTree(testedBinder), uniqueTp(pat.tpe)) def tru = True } ttm.renderCondition(condStrategy) diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index a80f158949..5d8a9fecef 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -447,8 +447,7 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { // - Scala's arrays are invariant (so we don't drop type tests unsoundly) if (extractorArgTypeTest) mkDefault else expectedTp match { - // TODO: [SPEC] the spec requires `eq` instead of `==` for singleton types - this implies sym.isStable - case SingleType(_, sym) => and(mkEqualsTest(gen.mkAttributedQualifier(expectedTp)), mkTypeTest) + case SingleType(_, sym) => mkEqTest(gen.mkAttributedQualifier(expectedTp)) // SI-4577, SI-4897 case ThisType(sym) if sym.isModule => and(mkEqualsTest(CODE.REF(sym)), mkTypeTest) // must use == to support e.g. List() == Nil case ConstantType(Constant(null)) if isAnyRef => mkEqTest(expTp(CODE.NULL)) case ConstantType(const) => mkEqualsTest(expTp(Literal(const))) diff --git a/test/files/run/t4577.scala b/test/files/run/t4577.scala new file mode 100644 index 0000000000..b08100d3ea --- /dev/null +++ b/test/files/run/t4577.scala @@ -0,0 +1,38 @@ +object Test { + val bippy = new Symbol("bippy") + val imposter = new Symbol("bippy") + val notBippy = new Symbol("not-bippy") + val syms = List(bippy, imposter, notBippy) + + // the equals method should only be used for case `bippy`, + // for the singleton type pattern, case _: bippy.type, the spec mandates `bippy eq _` as the test + class Symbol(val name: String) { + override def equals(other: Any) = other match { + case x: Symbol => name == x.name + case _ => false + } + override def toString = name + } + + // TODO: test bytecode equality for f and fDirect (and g and gDirect), + // for now the optimizer doesn't quite get from `f` to `fDirect` + def f(s: Symbol) = s match { + case _: bippy.type => true + case _ => false + } + def fDirect(s: Symbol) = bippy eq s + + def g(s: Symbol) = s match { + case _: bippy.type => 1 + case `bippy` => 2 + case _ => 3 + } + def gDirect(s: Symbol) = if (bippy eq s) 1 else if (bippy == s) 2 else 3 + + def main(args: Array[String]): Unit = { + // `syms map f` should be: true false false + assert(syms forall (s => f(s) == fDirect(s))) + // `syms map g` should be: 1 2 3 + assert(syms forall (s => g(s) == gDirect(s))) + } +} \ No newline at end of file -- cgit v1.2.3