Skip to content

Commit f8acad1

Browse files
committed
Fix @switch warnings for matches on value classes
Matches on value classes that have an underlying switchable type may be emitted as tableswitch or lookupswitch, but the shape of the result tree differs from ordinary switch-compiled matches. Previously, this caused a spurious warning to be issued if such a match was annotated with @switch, as none of the result cases were discovered by the warning logic, and hence the match was warned as having too few cases. With the warning for too few cases now removed, we have the opposite issue: in no circumstance is a switch warning issued for @switch annotated matches on value classes. This commit attempts to address this issue and restore the @switch warnings for those matches on value classes where a tableswitch or lookupswitch is not emitted. A complicating factor is that the original case types for matches on value class extractors are not singleton types, and so counting the number of unique types is not useful for determining the number of original cases.
1 parent e298e21 commit f8acad1

File tree

3 files changed

+36
-1
lines changed

3 files changed

+36
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,11 @@ object PatternMatcher {
981981
val resultCases = result match
982982
case Match(_, cases) => cases
983983
case Block(_, Match(_, cases)) => cases
984+
case Block((_: ValDef) :: Block(_, Match(_, cases)) :: Nil, _) => cases
984985
case _ => Nil
986+
val caseThreshold =
987+
if ValueClasses.isDerivedValueClass(tpt.tpe.typeSymbol) then 1
988+
else MinSwitchCases
985989
def typesInPattern(pat: Tree): List[Type] = pat match
986990
case Alternative(pats) => pats.flatMap(typesInPattern)
987991
case _ => pat.tpe :: Nil
@@ -990,7 +994,7 @@ object PatternMatcher {
990994
def numTypes(cdefs: List[CaseDef]): Int =
991995
typesInCases(cdefs).toSet.size: Int // without the type ascription, testPickling fails because of #2840.
992996
val numTypesInOriginal = numTypes(original.cases)
993-
if numTypesInOriginal >= MinSwitchCases && numTypes(resultCases) < numTypesInOriginal then
997+
if numTypesInOriginal >= caseThreshold && numTypes(resultCases) < numTypesInOriginal then
994998
patmatch.println(i"switch warning for ${ctx.compilationUnit}")
995999
patmatch.println(i"original types: ${typesInCases(original.cases)}%, %")
9961000
patmatch.println(i"switch types : ${typesInCases(resultCases)}%, %")

tests/neg-custom-args/fatal-warnings/switches.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,25 @@ object Main {
7676
case 1 | 2 | 3 => true
7777
case _ => false
7878
}
79+
80+
case class IntAnyVal(x: Int) extends AnyVal
81+
82+
val Ten = IntAnyVal(10)
83+
def fail5(x: IntAnyVal) = (x: @switch) match { // error: Could not emit switch for @switch annotated match
84+
case IntAnyVal(1) => 0
85+
case Ten => 1
86+
case IntAnyVal(100) => 2
87+
case IntAnyVal(1000) => 3
88+
case IntAnyVal(10000) => 4
89+
}
90+
91+
// the generated lookupswitch covers only a subset of the cases
92+
final val One = IntAnyVal(1)
93+
def fail6(x: IntAnyVal) = (x: @switch) match { // error: Could not emit switch for @switch annotated match
94+
case One => 0
95+
case IntAnyVal(10) => 1
96+
case IntAnyVal(100) => 2
97+
case IntAnyVal(1000) => 3
98+
case IntAnyVal(10000) => 4
99+
}
79100
}

tests/pos-special/fatal-warnings/switches.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,18 @@ class Test {
3333
case 1 | 2 | 3 => true
3434
case _ => false
3535
}
36+
37+
def test6(x: IntAnyVal) = (x: @switch) match {
38+
case IntAnyVal(1) => 0
39+
case IntAnyVal(10) => 1
40+
case IntAnyVal(100) => 2
41+
case IntAnyVal(1000) => 3
42+
case IntAnyVal(10000) => 4
43+
}
3644
}
3745

46+
case class IntAnyVal(x: Int) extends AnyVal
47+
3848
object Test {
3949
final val LF = '\u000A'
4050
final val CR = '\u000D'

0 commit comments

Comments
 (0)