Skip to content

Commit f2b453a

Browse files
committed
Fix #1463: no type cast in singelton equality test
1 parent 79ce6c0 commit f2b453a

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,12 +308,12 @@ object PatternMatcher {
308308
if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan
309309
else TestPlan(NonNullTest, scrutinee, tree.pos, unappPlan, onFailure)
310310
case Bind(name, body) =>
311-
val body1 = patternPlan(scrutinee, body, onSuccess, onFailure)
312-
if (name == nme.WILDCARD) body1
311+
if (name == nme.WILDCARD) patternPlan(scrutinee, body, onSuccess, onFailure)
313312
else {
313+
// The type of `name` may refer to val in `body`, therefore should come after `body`
314314
val bound = tree.symbol.asTerm
315315
initializer(bound) = ref(scrutinee)
316-
LetPlan(bound, body1)
316+
patternPlan(scrutinee, body, LetPlan(bound, onSuccess), onFailure)
317317
}
318318
case Alternative(alts) =>
319319
labelAbstract(onSuccess) { ons =>
@@ -839,7 +839,12 @@ object PatternMatcher {
839839
else
840840
If(emitCondition(plan).withPos(plan.pos), emit(plan.onSuccess), emit(plan.onFailure))
841841
case LetPlan(sym, body) =>
842-
seq(ValDef(sym, initializer(sym).ensureConforms(sym.info)) :: Nil, emit(body))
842+
sym.info match {
843+
case tmref: TermRef if tmref.isStable => // check #1463, no type cast needed
844+
seq(ValDef(sym, ref(tmref)) :: Nil, emit(body))
845+
case _ =>
846+
seq(ValDef(sym, initializer(sym).ensureConforms(sym.info)) :: Nil, emit(body))
847+
}
843848
case LabelledPlan(label, body, params) =>
844849
label.info = MethodType.fromSymbols(params, resultType)
845850
val labelDef = DefDef(label, Nil, params :: Nil, resultType, emit(labelled(label)))

tests/run/i1463.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object Test {
2+
case object Bob { override def equals(other: Any) = true }
3+
4+
class Bob2 {
5+
override def equals(other: Any) = true
6+
}
7+
val Bob2 = new Bob2
8+
9+
def f0(x: Any) = x match { case Bob2 => Bob2 } // class cast exception at runtime, dotc only
10+
def f1(x: Any) = x match { case Bob => Bob } // class cast exception at runtime, dotc only
11+
def f2(x: Any): Bob.type = x match { case x @ Bob => x } // class cast exception at runtime, dotc and javac.
12+
13+
def main(args: Array[String]): Unit = {
14+
assert(f0(Bob2) eq Bob2)
15+
assert(f0(0) eq Bob2) // only dotty fails here
16+
assert(f0(Nil) eq Bob2)
17+
18+
assert(f1(Bob) eq Bob)
19+
assert(f1(0) eq Bob) // only dotty fails here
20+
assert(f1(Nil) eq Bob)
21+
22+
assert(f2(Bob) eq Bob)
23+
assert(f2(0) eq Bob) // both dotty and scalac fail here
24+
assert(f2(Nil) eq Bob)
25+
}
26+
}

0 commit comments

Comments
 (0)