From dec8b972f5544a8fa6166a3f480eea6a255df4a9 Mon Sep 17 00:00:00 2001 From: liu fengyun Date: Wed, 16 Aug 2017 13:41:11 +0200 Subject: [PATCH] Fix #1463: no type cast in singelton equality test --- .../tools/dotc/transform/PatternMatcher.scala | 13 +++++++--- tests/run/i1463.scala | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 tests/run/i1463.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 5007f31007d6..c0142e6cd70e 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -308,12 +308,12 @@ object PatternMatcher { if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan else TestPlan(NonNullTest, scrutinee, tree.pos, unappPlan, onFailure) case Bind(name, body) => - val body1 = patternPlan(scrutinee, body, onSuccess, onFailure) - if (name == nme.WILDCARD) body1 + if (name == nme.WILDCARD) patternPlan(scrutinee, body, onSuccess, onFailure) else { + // The type of `name` may refer to val in `body`, therefore should come after `body` val bound = tree.symbol.asTerm initializer(bound) = ref(scrutinee) - LetPlan(bound, body1) + patternPlan(scrutinee, body, LetPlan(bound, onSuccess), onFailure) } case Alternative(alts) => labelAbstract(onSuccess) { ons => @@ -839,7 +839,12 @@ object PatternMatcher { else If(emitCondition(plan).withPos(plan.pos), emit(plan.onSuccess), emit(plan.onFailure)) case LetPlan(sym, body) => - seq(ValDef(sym, initializer(sym).ensureConforms(sym.info)) :: Nil, emit(body)) + (sym.info, initializer(sym)) match { + case (tmref: TermRef, _: RefTree) if tmref.isStable => // check #1463, no type cast needed + seq(ValDef(sym, ref(tmref)) :: Nil, emit(body)) + case (_, init) => + seq(ValDef(sym, init.ensureConforms(sym.info)) :: Nil, emit(body)) + } case LabelledPlan(label, body, params) => label.info = MethodType.fromSymbols(params, resultType) val labelDef = DefDef(label, Nil, params :: Nil, resultType, emit(labelled(label))) diff --git a/tests/run/i1463.scala b/tests/run/i1463.scala new file mode 100644 index 000000000000..f6c5d5229c44 --- /dev/null +++ b/tests/run/i1463.scala @@ -0,0 +1,26 @@ +object Test { + case object Bob { override def equals(other: Any) = true } + + class Bob2 { + override def equals(other: Any) = true + } + val Bob2 = new Bob2 + + def f0(x: Any) = x match { case Bob2 => Bob2 } // class cast exception at runtime, dotc only + def f1(x: Any) = x match { case Bob => Bob } // class cast exception at runtime, dotc only + def f2(x: Any): Bob.type = x match { case x @ Bob => x } // class cast exception at runtime, dotc and javac. + + def main(args: Array[String]): Unit = { + assert(f0(Bob2) eq Bob2) + assert(f0(0) eq Bob2) // only dotty fails here + assert(f0(Nil) eq Bob2) + + assert(f1(Bob) eq Bob) + assert(f1(0) eq Bob) // only dotty fails here + assert(f1(Nil) eq Bob) + + assert(f2(Bob) eq Bob) + assert(f2(0) eq Bob) // both dotty and scalac fail here + assert(f2(Nil) eq Bob) + } +}