Skip to content

Commit a007673

Browse files
committed
Fix pattern matching alternative/5402
1 parent dab02ed commit a007673

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -769,16 +769,31 @@ object PatternMatcher {
769769
}
770770

771771
/** Emit cases of a switch */
772-
private def emitSwitchCases(cases: List[(List[Tree], Plan)]): List[CaseDef] = (cases: @unchecked) match {
773-
case (alts, ons) :: cases1 =>
774-
val pat = alts match {
775-
case alt :: Nil => alt
776-
case Nil => Underscore(defn.IntType) // default case
777-
case _ => Alternative(alts)
772+
private def emitSwitchCases(cases: List[(List[Tree], Plan)]): List[CaseDef] = cases.foldLeft(List[CaseDef]()) {
773+
case (prev, (alts, ons)) =>
774+
val pat = simplifyCases(alts) match {
775+
case Alternative(als) =>
776+
simplifyCases(removeRedundantCases(prev.map(_.pat), als))
777+
case t => t
778778
}
779-
CaseDef(pat, EmptyTree, emit(ons)) :: emitSwitchCases(cases1)
780-
case nil =>
781-
Nil
779+
CaseDef(pat, EmptyTree, emit(ons)) :: prev
780+
}
781+
782+
/** Remove cases that already appear in the same pattern or in previous patterns */
783+
private def removeRedundantCases(previousCases: List[Tree], cases: List[Tree]): List[Tree] = cases.foldLeft(List[Tree]()) {
784+
case (cases, alt) =>
785+
if (cases.exists(_ === alt) || previousCases.exists(_ === alt)) {
786+
cases
787+
} else {
788+
alt :: cases
789+
}
790+
}
791+
792+
/** Flatten a list of patterns into a single tree */
793+
private def simplifyCases(alts: List[Tree]): Tree = alts match {
794+
case alt :: Nil => alt
795+
case Nil => Underscore(defn.IntType) // default case
796+
case _ => Alternative(alts)
782797
}
783798

784799
/** If selfCheck is `true`, used to check whether a tree gets generated twice */
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
object Main {
3+
val a: Int = 4
4+
a match {
5+
case 1 => println("1")
6+
case 1 | 2 => println("1 or 2")
7+
}
8+
9+
a match {
10+
case 1 => 1
11+
case 0 | 0 => 0
12+
case 2 | 2 | 2 | 3 | 2 | 3 => 0
13+
case 4 | (_ @ 4) => 0
14+
case _ => -1
15+
}
16+
17+
a match {
18+
case 1 => 1
19+
case 0 | 0 => 0
20+
case 2 | 2 | 2 | 3 | 2 | 3 => 0
21+
case _ => -1
22+
}
23+
}

0 commit comments

Comments
 (0)